我目前正在尝试学习Haskell,并且遇到了一个关于Maybe monad的奇怪问题,我似乎无法弄清楚。
作为一项实验,我目前正在尝试取一个字符串,将每个字母转换为任意数字,并将它们相乘/组合在一起。到目前为止,我的情况如下:
lookupTable :: [(Char, Int)]
lookupTable = [('A', 1), ('B', 4), ('C', -6)]
strToInts :: String -> [Maybe Int]
strToInts = map lookupChar
    where 
        lookupChar :: Char -> Maybe Int
        lookupChar c = lookup c lookupTable
-- Currently fails
test :: (Num n, Ord n) => [Maybe n] -> [Maybe n]
test seq = [ x * y | (x, y) <- zip seq $ tail seq, x < y ]
main :: IO ()
main = do
    putStrLn $ show $ test $ strToInts "ABC"当我尝试运行它时,它返回以下错误:
test.hs:13:16:
    Could not deduce (Num (Maybe n)) arising from a use of `*'
    from the context (Num n, Ord n)
      bound by the type signature for
                 test :: (Num n, Ord n) => [Maybe n] -> [Maybe n]
      at test.hs:12:9-48
    Possible fix: add an instance declaration for (Num (Maybe n))
    In the expression: x * y
    In the expression: [x * y | (x, y) <- zip seq $ tail seq]
    In an equation for `test':
        test seq = [x * y | (x, y) <- zip seq $ tail seq]我不能百分之百确定为什么会发生这个错误,也不确定它到底意味着什么,尽管我怀疑这可能是因为我试图将两个Maybe monads相乘--如果我将test的定义更改为以下内容,程序就会编译并运行良好:
test :: (Num n, Ord n) => [Maybe n] -> [Maybe n]
test seq = [ x | (x, y) <- zip seq $ tail seq, x < y ]我还尝试将类型声明更改为下面的内容,但这也不起作用。
test :: (Num n, Ord n) => [Maybe n] -> [Num (Maybe n)]我真不知道该怎么纠正这个错误。我对Haskell非常陌生,所以这可能只是我错过了一些非常简单的东西,或者我已经把所有的东西都安排得完全错误了,但这是在阻挠我。我做错了什么?
发布于 2014-03-08 11:33:15
Reite的答案是正确的,通常是我建议如何处理它--然而,在我看来,您似乎不太了解如何处理Maybe值;如果是这样的话,现在看应用程序函子就没什么意义了。
Maybe的定义基本上是
 data Maybe a = Nothing | Just a这基本上意味着,在通俗易懂的英语中,它听起来就像“Maybe a类型的值要么是该类型的值Nothing,要么是表单Just a的值”。
现在您可以使用模式匹配来处理这个问题了,下面是列表的例子:
 maybeReverse :: Maybe [a] -> Maybe [a]
 maybeReverse Nothing = Nothing
 maybeReverse (Just xs) = Just $ reverse xs这基本上意味着“如果值是Nothing,那么没有什么可逆转的,所以结果又是Nothing,如果值是Just xs,那么我们可以用Just重新包装它,将其转化为Maybe [a]值)。
当然,编写像这样的函数,对于我们想要使用的每一个Maybe值来说都是乏味的;因此,更高级的函数来拯救我们吧!这里的观察是,在maybeReverse中,我们没有对reverse做太多事情,我们只是将它应用到包含的值中,并在Just中封装了结果。
因此,我们可以编写一个名为liftToMaybe的函数,为我们这样做:
 liftToMaybe :: (a->b) -> Maybe a -> Maybe b
 liftToMaybe f Nothing = Nothing
 liftToMaybe f (Just a) = Just $ f a我们还可以进一步观察到,因为函数是值,所以我们也可以有函数的Maybe值。为了做任何有用的事情,我们可以再次打开它们.或者,注意到我们处于与最后一段相同的情况,并立即注意到我们并不真正关心Maybe值中究竟存在什么函数,只需直接编写抽象:
 maybeApply :: Maybe (a->b) -> Maybe a -> Maybe b
 maybeApply Nothing _ = Nothing
 maybeApply _ Nothing = Nothing
 maybeApply (Just f) (Just a) = Just $ f a使用上面的liftToMaybe函数,我们可以简化一点:
 maybeApply :: Maybe (a->b) -> Maybe a -> Maybe b
 maybeApply Nothing _ = Nothing
 maybeApply (Just f) x = liftToMaybe f xReite的答案中的<$>和<*>运算符基本上只是liftToMaybe (也称为fmap)和maybeApply的infix名称;它们有以下类型
(<$>) :: Functor f => (a->b) -> f a -> f b
(<*>) :: Applicative f => f (a->b) -> f a -> f b您现在并不需要知道Functor和Applicative是什么东西(尽管您应该在某个时候研究它们;它们基本上是对其他类型的“上下文”的上述Maybe函数的概括)--基本上,只需用Maybe替换f,您就会发现这些函数基本上都是我们前面讨论过的函数。
现在,我把这个应用到你原来的乘法问题上(尽管其他的答案有点坏了)。
https://stackoverflow.com/questions/22268226
复制相似问题