'what is the correct Haskell syntax for this 'where' clause?
what is the appropriate correction for this syntax? Is it an issue white space? I copied the whitespace used in examples in LYAH, also tried other variations gleaned from answers on SO.
I'm sure there's better ways to write this, but I'm not really any good at point free code yet. I'm novice level and trying to master the very elementary syntax things that continue to trip me up by doing lots of codewars exercises.
import Data.List (findIndices)
basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations !! (op x)) y z
where op x = head $ findIndices (== x) "+-*/" :: Char -> Int
operations = [(+), (-), (*), (div)] :: [(Int -> Int -> Int)]
when I write like this as one function making reference to two other functions it works.
import Data.List (findIndices)
operations :: [(Int -> Int -> Int)]
operations = [(+), (-), (*), (div)]
op :: Char -> Int
op x = head $ findIndices (== x) "+-*/"
basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations !! (op x)) y z
the code with the where clause returns these errors:
codewars.hs:103:34: error:
• Couldn't match expected type ‘Int’ with actual type ‘Char -> Int’
• Probable cause: ‘op’ is applied to too few arguments
In the second argument of ‘(!!)’, namely ‘(op x)’
In the expression: (operations !! (op x)) y z
In an equation for ‘basicOp’:
basicOp x y z
= (operations !! (op x)) y z
where
op x = head $ findIndices (== x) "+-*/" :: Char -> Int
operations = [(+), ....] :: [(Int -> Int -> Int)]
|
103 | basicOp x y z = (operations !! (op x)) y z
| ^^^^
codewars.hs:104:18: error:
• Couldn't match expected type ‘Char -> Int’ with actual type ‘Int’
• Possible cause: ‘($)’ is applied to too many arguments
In the expression: head $ findIndices (== x) "+-*/" :: Char -> Int
In an equation for ‘op’:
op x = head $ findIndices (== x) "+-*/" :: Char -> Int
In an equation for ‘basicOp’:
basicOp x y z
= (operations !! (op x)) y z
where
op x = head $ findIndices (== x) "+-*/" :: Char -> Int
operations = [(+), ....] :: [(Int -> Int -> Int)]
|
104 | where op x = head $ findIndices (== x) "+-*/" :: Char -> Int
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
my original attempt is probably easier to read, but this is just an exercise to try and use more Haskell constructs which I'm not familiar with yet.
basicOp :: Char -> Int -> Int -> Int
basicOp oper x y
| oper == '+' = (+) x y
| oper == '-' = (-) x y
| oper == '*' = (*) x y
| oper == '/' = (div) x y
From the comments, by @DanielWagner, this is improved to:
basicOp c = case c of
'+' -> (+)
'-' -> (-)
'*' -> (*)
'/' -> div
Solution 1:[1]
The type of the body of the op x expression is an Int, not a Char -> Int. You should also position operations at the same column as op, so:
basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations !! (op x)) y z
where op x = head $ findIndices (== x) "+-*/" :: Int
operations = [(+), (-), (*), (div)] :: [(Int -> Int -> Int)]
But the types are not necessary, you can simplify this to:
basicOp :: Char -> Int -> Int -> Int
basicOp x = (operations !! op x)
where op x = head $ findIndices (== x) "+-*/"
operations = [(+), (-), (*), (div)]
and work with lookup :: Eq a => a -> [(a, b)] -> Maybe b:
basicOp :: Char -> Int -> Int -> Int
basicOp x | Just y <- lookup x operations = y
| otherwise = …
where operations = [('+', (+)), ('-', (-)), ('*', (*)), ('/', div)]
where … is an expression that is then evaluated if the key is not found
Solution 2:[2]
Note that you can provide a type for the function itself, either on a separate line
basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations !! (op x)) y z
where
op :: Char -> Int
op x = head $ findIndices (== x) "+-*/"
operations = [(+), (-), (*), (div)] :: [(Int -> Int -> Int)]
or by providing an explicit lambda expression as the value for op.
basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations !! (op x)) y z
where op = (\x -> head $ findIndices (== x) "+-*/") :: Char -> Int
operations = [(+), (-), (*), (div)] :: [(Int -> Int -> Int)]
Solution 3:[3]
Oh, removing the type declarations for op and operations works.
I thought it was ok (helpful even) to put type declarations "inline" sometimes.
basicOp :: Char -> Int -> Int -> Int
basicOp x y z = (operations !! (op x)) y z
where
op x = head $ findIndices (== x) "+-*/"
operations = [(+), (-), (*), (div)]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | leftaroundabout |
| Solution 3 | wide_eyed_pupil |
