patternMinor
Ricochet Challenge: Robust IO and working with different types of numbers in Haskell
Viewed 0 times
robustchallengewithnumbersworkingdifferentricochethaskelltypesand
Problem
Background
I've tried to solve /r/DailyProgrammer Challenge #303 [Easy]: Ricochet (summarised below) in Haskell. The code below is now the second Haskell script I've ever written, so I'd consider myself quite the beginner. It works (to a bare minimum), but I'm not particularly happy with it.
My knowledge in Haskell at this point spans as far as the first two chapters of the fantastic Haskell Wikibook. I've not reached functors, monads, or friends, so if the solutions to my queries lie there then it might be wisest for me to settle until I learn more.
My Queries
Whilst I'm sure there are many problems, my main concerns in the code below regard the manner in which I'm dealing with the numerical arguments to
More particularly, regarding
And regarding IO:
However, I'd of course appreciate any advice at all, even around spacing/indentation!
```
#!/usr/bin/env stack
-- stack --resolver=lts-8.2 --install-ghc runghc
{-
Rico
I've tried to solve /r/DailyProgrammer Challenge #303 [Easy]: Ricochet (summarised below) in Haskell. The code below is now the second Haskell script I've ever written, so I'd consider myself quite the beginner. It works (to a bare minimum), but I'm not particularly happy with it.
My knowledge in Haskell at this point spans as far as the first two chapters of the fantastic Haskell Wikibook. I've not reached functors, monads, or friends, so if the solutions to my queries lie there then it might be wisest for me to settle until I learn more.
My Queries
Whilst I'm sure there are many problems, my main concerns in the code below regard the manner in which I'm dealing with the numerical arguments to
ricochet, and the fragile nature of IO.More particularly, regarding
ricochet:- I wanted the 5 arguments (namely
h,w,m,nandv) all to be any kind of integer (not mindingIntorInteger, etc., so long as it's a whole number, mathematically speaking), barringvwhich can be any number at all (i.e. 1.05).
- Whilst need for integers is important (as modulo (and thus the algorithm) wouldn't make sense without them), I also want to be able to perform arbitrary arithmetic, including any kind of division.
- I took me much time and frustration to come up with anything that'd even compile, for what's considerably basic arithmetic, and at the end I still find that function signature and spam
fromIntegralnasty. Any advice on dealing with this kind of situation in future?
And regarding IO:
- What's there now is the bare minimum to work with the challenge. I'm not happy with it because it's so fragile. If anything at all is wrong with the input, the whole program explodes.
- I'd rather just output a blank line if the input is invalid, but I've no idea how to get that done.
However, I'd of course appreciate any advice at all, even around spacing/indentation!
```
#!/usr/bin/env stack
-- stack --resolver=lts-8.2 --install-ghc runghc
{-
Rico
Solution
You can reduce the
The return value of functions like
But what if you want to keep the explicit signatures, for clarity? You can use "explicit forall" along with the
fromIntegral spam like this:ricochet :: (Integral a, Fractional b) => a -> a -> a -> a -> b -> (Corner, a, b)
ricochet h w m n v
= (c,b,fromIntegral d / v)
where
h' = h - m
w' = w - n
d = lcm w' h'The return value of functions like
- and lcm is of the same type as their arguments, so the types of h' and the like can be inferred. You do need to write fromIntegral d / v because the compiler doesn't perform automatically the conversion required for the division operator. It's frequent to have these conversions functions at "type cast" boundaries.But what if you want to keep the explicit signatures, for clarity? You can use "explicit forall" along with the
ScopedTypeVariables extension, which allow you to say "this type here is the exact same type as the type in the top-level signature".{-# LANGUAGE ScopedTypeVariables #-}
module Main
( Corner(..)
, ricochet
, main
) where
data Corner = UL | UR | LR | LL deriving (Show, Eq)
ricochet :: forall a b. (Integral a, Fractional b)
=> a -> a -> a -> a -> b -> (Corner, a, b)
ricochet h w m n v
= (c,b,fromIntegral d / v)
where
h', w', d :: a
h' = h - m
w' = w - n
d = lcm w' h'Code Snippets
ricochet :: (Integral a, Fractional b) => a -> a -> a -> a -> b -> (Corner, a, b)
ricochet h w m n v
= (c,b,fromIntegral d / v)
where
h' = h - m
w' = w - n
d = lcm w' h'{-# LANGUAGE ScopedTypeVariables #-}
module Main
( Corner(..)
, ricochet
, main
) where
data Corner = UL | UR | LR | LL deriving (Show, Eq)
ricochet :: forall a b. (Integral a, Fractional b)
=> a -> a -> a -> a -> b -> (Corner, a, b)
ricochet h w m n v
= (c,b,fromIntegral d / v)
where
h', w', d :: a
h' = h - m
w' = w - n
d = lcm w' h'Context
StackExchange Code Review Q#156273, answer score: 3
Revisions (0)
No revisions yet.