Haskell IO Bool 折叠问题

发布于 2024-10-07 01:21:27 字数 267 浏览 0 评论 0原文

如何编写一个在列表元素之间执行逻辑和功能的函数?

我是这样写的:

iand :: [IO Bool] -> IO Bool

iand [] = return (True)
iand (x:xs) = do
  a <- x 
  b <- iand(xs)
  return (a && b)

但这似乎是不良心的。

如何用foldM(liftM)重写这个函数?

谢谢。

How can I write a function that does logical and function between the elements of the list?

I have written this:

iand :: [IO Bool] -> IO Bool

iand [] = return (True)
iand (x:xs) = do
  a <- x 
  b <- iand(xs)
  return (a && b)

But that seems to be unconscice.

How can this function be rewritten with foldM (liftM)?

Thank you.

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

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

发布评论

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

评论(3

沩ん囻菔务 2024-10-14 01:21:27

Prelude 函数 和 :: [布尔] -> Bool 几乎可以满足您的要求,但它不是单子。一般来说,要将单参数函数提升为 monad,您需要 Control.Monad 的 liftM :: Monad m => (a→b)→妈-> b a;但是,更一般地说,您可以使用 Prelude 的 fmap :: 函子 f => (a→b)→发-> fb。所有 monad 都是函子1,所以这是可以的。因此,您可以使用

fand' :: Functor f => f [Bool] -> f Bool
fand' = fmap and

然而,至少 90% 的时间,我只是将内联编写为 fmap 和 xs,或者更可能的是 and <$>; xs,使用 Control.Applicative 的 <$>fmap 的同义词。

当然,我相信您已经注意到,这不是您想要的。为此,您需要 Prelude 的 序列:: Monad m => [ma]-> m [a]。你现在有一个函数 [ma] -> m [a] 和函数 f [Bool] -> f Bool,所以我们可以将这些结合起来:

mand :: Monad m => [m Bool] -> m Bool
mand = liftM and . sequence

我从 fmap 切换到 liftM,因为尽管 fmap 在从某种意义上说,它会施加一个额外的函子 m 约束。这不应该是一个问题,但这可能是由于历史原因,所以我谨慎行事。

另外,您可能会问“我怎么会知道序列”?答案是精彩的 Hoogle,它允许您按名称搜索 Haskell 函数或输入。所以,既然你知道 liftM :: Monad m =>; (a→b)→妈-> m b,您可能已经意识到您需要类似 Monad m =>; [ma]-> m[a];寻找那个 确实出现了序列


1:或者,至少,它们应该是这样的——但由于历史原因,情况并非总是如此。

The Prelude function and :: [Bool] -> Bool almost does what you want, but it's not monadic. Generally speaking, to lift a one-argument function into a monad, you'll want Control.Monad's liftM :: Monad m => (a -> b) -> m a -> b a; however, to be more general, you can use the Prelude's fmap :: Functor f => (a -> b) -> f a -> f b. All monads are functors1, so this is ok. Thus, you can use

fand' :: Functor f => f [Bool] -> f Bool
fand' = fmap and

However, at least 90% of the time, I would just write that inline as fmap and xs, or more probably and <$> xs, using Control.Applicative's <$> synonym for fmap.

Of course, as I'm sure you noticed, this isn't what you want. For that, you need the Prelude's sequence :: Monad m => [m a] -> m [a]. You now have a function [m a] -> m [a], and a function f [Bool] -> f Bool, so we can combine these:

mand :: Monad m => [m Bool] -> m Bool
mand = liftM and . sequence

I switched to liftM from fmap because, although fmap's "nicer" in some sense, it would impose an additional Functor m constraint. That shouldn't be a problem, but it could be for historical reasons, so I played it safe.

Also, you might ask "How would I have ever known about sequence"? The answer to that is the wonderful Hoogle, which allows you to search for Haskell functions by name or type. So, since you knew about liftM :: Monad m => (a -> b) -> m a -> m b, you might have realized you needed something like Monad m => [m a] -> m [a]; Hoogling for that does indeed turn up sequence.


1: Or, at least, they should be—for historical reasons, though, this isn't always the case.

一个人的旅程 2024-10-14 01:21:27

您可以使用 liftMand (其类型为 [Bool] -> Bool)转换为 IO 类型的函数 [布尔]-> IO Boolsequence 将您的 [IO Bool] 转换为 IO [Bool]

所以你的函数就变成了:

iand ibs = liftM and (sequence ibs)

You can use liftM to turn and (which has type [Bool] -> Bool) into a function of type IO [Bool] -> IO Bool and sequence to turn your [IO Bool] into an IO [Bool].

So your function becomes:

iand ibs = liftM and (sequence ibs)
故事与诗 2024-10-14 01:21:27

这不是 iand list = Foldl (&&) True list 吗?

Wouldn't this be iand list = foldl (&&) True list ?

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