我的递归列表构造有什么问题?

发布于 2024-12-17 07:28:04 字数 947 浏览 2 评论 0原文

我已经简化了相关功能。我在 monad 内构建列表时遇到问题。我怀疑存在优先级问题。

newtype Boundary = MkBoundary Integer

testFunc :: [Boundary] -> [Maybe Integer]
testFunc (MkBoundary x:xs)
   | (even x) = Just x : testFunc xs
   | otherwise = Nothing : testFunc xs
testFunc _ = []

这按预期工作。但我需要在一个单子中工作。在这个例子中我将使用 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。我做错了什么?

I've simplified the functions in question. I'm having trouble constructing a list inside a monad. I suspect a precedence problem.

newtype Boundary = MkBoundary Integer

testFunc :: [Boundary] -> [Maybe Integer]
testFunc (MkBoundary x:xs)
   | (even x) = Just x : testFunc xs
   | otherwise = Nothing : testFunc xs
testFunc _ = []

This works as expected. But I need to work in a monad. I'll use IO for this example

testFunc :: [Boundary] -> IO [Maybe Integer]
testFunc (MkBoundary x:xs)
   | (even x) = return $ Just x : testFunc xs
   | otherwise = return $ Nothing : testFunc xs
testFunc _ = []

No matter how I try to manipulate precedence, this breaks.

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.

What I am trying to accomplish is a constructing a list, then returning it to IO. What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

止于盛夏 2024-12-24 07:28:04

luqui 回答了你的问题,我会注意到一个有用的组合器。

如果要对列表的所有元素执行单子操作,请使用“mapM”。它被定义为:

 mapM f [] = return []
 mapM f (x:xs) = do y <- f x
                    ys <- mapM f xs
                    return (y:ys)

或等效的东西。 [如果您知道其他一些组合器,可以使用 liftM2foldr 编写 mapM。]

 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]

luqui answered your question, I will note a useful combinator.

If you want to perform a monadic action for all elements of a list, use "mapM". It is defined as:

 mapM f [] = return []
 mapM f (x:xs) = do y <- f x
                    ys <- mapM f xs
                    return (y:ys)

or something equivalent. [If you know some other combinators, you can write mapM with liftM2 and foldr.]

 testFunc = mapM f
     where f (MkBoundary x) | even x = do print x
                                          return $ Just x
                            | otherwise = return Nothing

test in GHCi:

*Main> testFunc [MkBoundary 2, MkBoundary 3, MkBoundary 4]
2
4
[Just 2,Nothing,Just 4]
霞映澄塘 2024-12-24 07:28:04

问题是 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 :) <
gt; testFunc xs

((<$>) 来自 Control.Applicative 并具有

(<
gt;) :: (a -> b) -> IO a -> IO b

专门针对 < code>IO 。它将函数应用于一元计算“内部”的值。)

哦,还有missingno所说的:-)

The problem is that testFunc xs returns an IO [Maybe Integer], and you are using it as the tail of a list as if it were a [Maybe Integer]. You need to extract:

| (even x) = do
    xs' <- testFunc xs
    -- now xs' is of type [Maybe Integer]
    return $ Just x : xs'

Or, a more succinct way of saying the same thing:

| (even x) = (Just x :) <
gt; testFunc xs

((<$>) is from Control.Applicative and has type

(<
gt;) :: (a -> b) -> IO a -> IO b

specialized to IO . It applies a function to the value "inside" a monadic computation.)

Oh, also what missingno said :-)

百变从容 2024-12-24 07:28:04

您忘记更改第二种情况

test_func _ = return []
           -- ^^^^^^

另外,我认为您的示例函数可以写得更清楚,因为

test_func :: [Boundary] -> [Maybe Integer]
test_func = ...

monadic_test_func = [Boundary] -> IO [Maybe Integer]
monadic_test_func = return . test_func

这使纯代码与讨厌的 monad 东西分开。它还可以让您不必输入三次“return”! :)


最后,你为什么要创建这样一个函数? monad 部分(至少在您的示例中)似乎与主函数逻辑有些无关(因为您只是执行return)。

也许您使用一些不错的库函数来保持您的函数纯净且不受影响?

--instead of 
monadic_value >>= monadic_test_func

--use
fmap test_func monadic_value
-- or equivalently
test_func <
gt; monadic_value
liftM test_func monadic_value

You forgot to change the second case

test_func _ = return []
           -- ^^^^^^

Also, I think your example function could be more clearly written as

test_func :: [Boundary] -> [Maybe Integer]
test_func = ...

monadic_test_func = [Boundary] -> IO [Maybe Integer]
monadic_test_func = return . test_func

This keeps the pure code separated from the nasty monad stuff. It also saves you from having to type "return" thrice! :)


And finally, why are you creating such a function in the first place? The monad part (at least in your example) seems to be somewhat unrelated to the main function logic (since you are just doing a return).

Perhaps you use some nice library functions to keep your function pure and untouched?

--instead of 
monadic_value >>= monadic_test_func

--use
fmap test_func monadic_value
-- or equivalently
test_func <
gt; monadic_value
liftM test_func monadic_value
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文