我有以下功能:
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)
如果l'&lt; 1400,在l'> 1的情况下,应创建并返回值m2。 1400我最终想要调用第二个函数,但在这种情况下,现在只返回m或者m就足够了。
我从警卫开始,并立即在错误中运行
No instance for (Monad (Map.Map (String, Integer)))
arising from a use of `return'
然后我尝试了if-then-else,不得不解决一些误解,并最终得到了同样的错误。
我想知道如何解决这个问题。我确实理解Monad是什么,或者Haskell中的数据是不可变的。然而,在阅读了两本关于Haskell的书之后,我觉得还有很远的地方可以编写一些有用的东西。总有一个Monad ......:D。
答案 0 :(得分:4)
您声明您的功能结果是
Map.Map (String, Integer) [String]
并且,通过使用return
,声明它也是monadic。因此,编译器认为Monad
应该有一个Map (String, Integer)
实例。
但是我很确定如果你放弃return
和do
并在in
之前写if
,这将会编译。或者至少它会给你更有意义的错误信息。
答案 1 :(得分:4)
这看起来非常像你对return
所做的事感到困惑。与许多命令式语言不同,return
不就像从函数返回值一样。
在Haskell中,您可以通过说f a b c = some_expression
之类的内容来定义函数。右侧是函数“返回”的表达式。你不需要在命令式语言中使用“返回语句”,事实上它没有意义。在命令式语言中,函数是一系列执行的语句,它很自然地适用于使用 return语句来确定函数的结果,该语句终止函数并传递一个值。在Haskell中,函数的右侧是一个单独的表达式,并且突然在该表达式的中间放置一个语句,以某种方式终止对表达式的求值并返回其他内容并不是真的有意义。
实际上,return
本身就是一个函数,而不是一个语句。它的命名可能很差,因为它不是那些学习Haskell的命令式程序员所期望的。 return foo
是将foo
包装成monadic值的方式;它对流控制没有任何影响,但只是在你正在使用的monad的上下文中求值为foo
。看起来你根本就没有使用monad(如果你的话,你的函数的类型肯定是错的。)
值得注意的是,如果/ then / else也不是Haskall中的声明;整个if / then / else块是一个表达式,它根据条件的值计算then
表达式或else
表达式。
所以带走do
,它只是提供了使用monad的方便语法。然后,您不需要return
任何内容,只需将m2
作为then
分支(使用let
绑定,或者只使用m2
一次您可以在then
分支中用Map.adjust (++ [a]) (b, c) m
)和m
替换整个else
表达式。然后,将其包装在let ... in ...
块中,以获得l
和l'
的绑定。整个let ... in ...
构造也是一个表达式,因此它可以就像你的函数定义的右边一样。没有do
,没有return
。