我简化了有问题的功能。我在monad中构建一个列表时遇到了麻烦。我怀疑是一个优先问题。
newtype Boundary = MkBoundary Integer
testFunc :: [Boundary] -> [Maybe Integer]
testFunc (MkBoundary x:xs)
| (even x) = Just x : testFunc xs
| otherwise = Nothing : testFunc xs
testFunc _ = []
这可以按预期工作。但我需要在monad中工作。我会在这个例子中使用IO
testFunc :: [Boundary] -> IO [Maybe Integer]
testFunc (MkBoundary x:xs)
| (even x) = return $ Just x : testFunc xs
| otherwise = return $ Nothing : testFunc xs
testFunc _ = []
无论我如何操纵优先权,这都会破坏。
test.hs:6:35:
Couldn't match expected type `[Maybe Integer]'
with actual type `IO [Maybe Integer]'
In the return type of a call of `testFunc'
In the second argument of `(:)', namely `testFunc xs'
In the second argument of `($)', namely `Just x : testFunc xs'
Failed, modules loaded: none.
我想要完成的是构建一个列表,然后将其返回给IO。我做错了什么?
答案 0 :(得分:5)
luqui回答了你的问题,我会注意到一个有用的组合。
如果要对列表的所有元素执行monadic操作,请使用“mapM”。它被定义为:
mapM f [] = return []
mapM f (x:xs) = do y <- f x
ys <- mapM f xs
return (y:ys)
或类似的东西。 [如果您了解其他一些组合器,可以使用mapM
和liftM2
撰写foldr
。]
testFunc = mapM f
where f (MkBoundary x) | even x = do print x
return $ Just x
| otherwise = return Nothing
在GHCi中进行测试:
*Main> testFunc [MkBoundary 2, MkBoundary 3, MkBoundary 4]
2
4
[Just 2,Nothing,Just 4]
答案 1 :(得分:4)
您忘记更改第二种情况
test_func _ = return []
-- ^^^^^^
另外,我认为您的示例函数可以更清楚地写为
test_func :: [Boundary] -> [Maybe Integer]
test_func = ...
monadic_test_func = [Boundary] -> IO [Maybe Integer]
monadic_test_func = return . test_func
这使纯代码与令人讨厌的monad东西分开。它还可以避免输入“返回”三次! :)
最后,你为什么要首先创造这样的功能? monad部分(至少在你的例子中)似乎与主函数逻辑有些无关(因为你只是做return
)。
也许您使用了一些很好的库函数来保持您的函数纯粹和不受影响?
--instead of
monadic_value >>= monadic_test_func
--use
fmap test_func monadic_value
-- or equivalently
test_func <$> monadic_value
liftM test_func monadic_value
答案 2 :(得分:4)
问题在于testFunc xs
会返回IO [Maybe Integer]
,您将其用作列表的尾部,就好像它是[Maybe Integer]
一样。你需要提取:
| (even x) = do
xs' <- testFunc xs
-- now xs' is of type [Maybe Integer]
return $ Just x : xs'
或者,更简洁的方式说同样的事情:
| (even x) = (Just x :) <$> testFunc xs
((<$>)
来自Control.Applicative
且类型为
(<$>) :: (a -> b) -> IO a -> IO b
专门针对IO
。它将函数应用于monadic计算中的“内部”值。)
哦,也是missno所说的: - )