if-then-else在这里出了什么问题?

时间:2012-02-13 22:53:06

标签: haskell

我已经尝试过多种方式:if-then-else,guards,case statement但是我从来没有设法让它编译。我认为从代码中我很清楚我想做什么。为什么这不可能,我该怎样做才能直截了当?

appendMsg :: String -> (String, Integer) -> Map.Map (String, Integer) [String] -> Map.Map (String, Integer) [String]
appendMsg  a (b,c) m = do
      let Just le1 = length . concat <$> Map.lookup (b,c) m
          le2 = le1 + length a
      if le2 < 1400 then (let m2 = Map.adjust (x ++ [a]) (b, c) m) else (print (le1, le2))
      return (m2)

我收到的错误消息是parse error on input `)'。如果我更改括号,我会parse error on input `else'。如果我在else路径中说(让m2 = m)那么我再次得到括号错误。

我试图实现的是,如果le2 <= 1400,则应使用

创建m2
f x = x ++ [a]
m2 = Map.adjust f (b, c) m

如果le2> 1400然后应该调用另一个函数,它接受与appendMsg相同的参数,而appendMsg应该只返回任何内容。

另一个问题是,只要根据以下所有建议正确设置:

if le2 < 1400 then let m2 = Map.adjust (++ [a]) (b, c) m in return (m2) else return ()

我收到错误说

 No instance for (Monad (Map.Map (String, Integer)))
      arising from a use of `return'

这就是我使用警卫时最终得到的同样错误。问题是,在这个奇怪的类型的剩余代码中我几乎无能为力。我可以以任何方式将此类型转换回(Map.Map(String,Integer)[String])或完全避免它吗?

2 个答案:

答案 0 :(得分:4)

let必须后跟in或直接位于do块内。 let不能是do块中的最后一个语句。这些规则的结果是,在没有任何使用机会的情况下创建一个超出范围的变量是没有意义的。

在您的代码中,您在m2的{​​{1}}分支内创建了一个名为then的变量,但您从未使用它。您(尝试)在if之外使用它,但在if if之外不存在。您不能使用在m2之外的if内创建的变量。当if条件为假时,m2的值应该是多少?

答案 1 :(得分:2)

您正在使用do,其结果必须是Monad实例,但您的函数类型表示它返回的Map不是Monad的实例。如果您真的想在Nothing时返回le2 >= 1400,那么您必须在Just ...时返回le2 < 1400,并且您的功能可能如下所示:

import qualified Data.Map as Map
import Control.Monad

appendMsg :: String -> (String, Integer) ->
             Map.Map (String, Integer) [String] ->
             Maybe (Map.Map (String, Integer) [String])
appendMsg  a k m = do
      v <- Map.lookup k m
      let l = length . concat $ v 
          l' = l + length a
      guard $ l' < 1400
      return $ Map.insert k (v ++ a) m

请注意,如果在Nothing中找不到以...开头的密钥,此函数将返回Map