I have a Haskell Map, containing strings as keys and some lambda functions as items . Eg.:
-- List of supported Operators -> mapping with functions
开发者_如何学Cops = Map.fromList [("+", \x y -> x + y),
("-", \x y -> y - x),
("*", \x y -> x * y),
("/", \x y -> y / x)]
I want to write a function that takes as input:
- A string representing an operator ["+", "-", "*", "/"]
- Two numbers
Based on the operator and the ops map, the function will evaluate the sum/subtraction/etc. of the two numbers .
I've tried something like:
(Map.lookup "+" a) 1 2
But it's not working .
The error is:
Top level:
No instance for (Show (Integer -> Integer))
arising from use of `print' at Top level
Probable fix: add an instance declaration for (Show (Integer
In a 'do' expression: print it
<interactive>:1:1:
No instance for (Monad ((->) t))
arising from use of `Data.Map.lookup' at <interactive>:1:1-
Probable fix: add an instance declaration for (Monad ((->) t)
In the definition of `it': it = (Data.Map.lookup "+" a) 1 2
... not very helpful for me.
Any suggestions ? Thank you !
lookup is of type lookup :: Ord k => k -> Map k a -> Maybe a
. The result is wrapped in a Maybe to indicate that the key may not be present in the map.
Here's a way to do it that will work:
runOp :: String -> a -> a -> b
runOp key x y = case lookup key ops of
Just op -> op x y
Nothing -> error ("Couldn't find operator: " ++ key)
This will bottom out if the key is not present. You could also return an Either
or Maybe
result from runOp to accommodate the possibility that the key isn't present, but that's up to you.
Maybe is defined as follows:
data Maybe a = Just a | Nothing
that is, it either holds a result value or an empty value. Like an existential philosopher, Haskell forces you to acknowledge the possibility of Nothing
.
First of all the error you showed is not caused by the code you showed. Your code causes the following error (in ghc):
Couldn't match expected type `t1 -> t2 -> t'
against inferred type `Data.Maybe.Maybe
That error is caused by the fact that lookup
returns a Maybe
. So you need to unwrap the Maybe
first.
import Control.Applicative
ops :: (Fractional a) => Map.Map String (a -> a -> a)
ops = Map.fromList [("+", (+)),
("-", flip (-)),
("*", (*)),
("/", flip (/))]
apply :: (Fractional a) => String -> a -> a -> Maybe a
apply op x y = Map.lookup op ops <*> y <*> x
Because lookup
returns a Maybe a
(well, Maybe (a -> a -> a)
in this case), there is no way to directly apply it to an a
. We can use <*>
to pull the LHS out of the mote, apply it to the RHS, and inject it back into the monad. (Or do it manually like Bill.)
精彩评论