I have the following function:
appendMsg :: String -> (String, Integer) -> Map.Map (String, Integer) [String] -> Map.Map (String, Integer) [String]
appendMsg a (b,c) m = do
let Just l = length . concat <$> Map.lookup (b,c) m
l' = l + length a
--guard $ l' < 1400
--return $ Map.adjust (++ [a]) (b, c) m
if l' < 1400 then let m2 = Map.adjust (++ [a]) (b, c) m in return m2 else return (m)
In case l’ < 1400 the value m2 should be created and returned, in case l’ > 1400 I eventually want to call a second function but for now it is sufficient to return nothing or m in this case.
I started with guards and was immediately running in the error
No instance for (Monad (Map.Map (String, Integer)))
arising from a use of `return'
Then I tried if-then-else, had to fix some misunderstanding and eventually ended up with the very same error.
I want to know how to fix this. I do understand what a Monad is or that Data in Haskell is immutable. However, after reading two books on Haskell I feel still quite far away from being in a position to code something useful. There is always one more Monad … 😀 .
This looks very much like you’re confused about what
returndoes. Unlike in many imperative languages,returnis not the way you return a value from a function.In Haskell you define a function by saying something like
f a b c = some_expression. The right hand side is the expression that the function “returns”. There’s no need for a “return statement” as you would use in imperative languages, and in fact it wouldn’t make sense. In imperative languages where a function is a sequence of statements that are executed, it fits naturally to determine what result the function evaluates to with a return statement which terminates the function and passes a value back up. In Haskell, the right hand side of your function is a single expression, and it doesn’t really make sense to suddenly put a statement in the middle of that expression that somehow terminates evaluation of the expression and returns something else instead.In fact,
returnis itself a function, rather than a statement. It was perhaps poorly named, given that it isn’t what imperative programmers learning Haskell would expect.return foois how you wrapfooup into a monadic value; it doesn’t have any effect on flow control, but just evaluates tofooin the context of whatever monad you’re using. It doesn’t look like you’re using monads at all (certainly the type for your function is wrong if you are).It’s also worth noting that if/then/else isn’t a statement in Haskall either; the whole if/then/else block is an expression, which evaluates to either the
thenexpression or theelseexpression, depending on the value of the condition.So take away the
do, which just provides convenient syntax for working with monads. Then you don’t need toreturnanything, just havem2as yourthenbranch (with theletbinding, or since you only usem2once you could just replace your wholethenexpression withMap.adjust (++ [a]) (b, c) m), andmin yourelsebranch. You then wrap that in alet ... in ...block to get your bindings oflandl'. And the wholelet ... in ...construct is also an expression, so it can just be the right hand side of your function definition as-is. Nodo, noreturn.