gpt4 book ai didi

haskell - 在 append 下保持 IO 惰性

转载 作者:行者123 更新时间:2023-12-01 01:48:01 25 4
gpt4 key购买 nike

我可能一直认为 Haskell 比它更懒惰,但我想知道是否有一种方法可以两全其美......
Data.MonoidData.Semigroup定义 First 的两个变体. monoidal 版本对最左边的非空值进行建模,而 semigroup 版本只是对最左边的值进行建模。

这适用于纯值值,但考虑不纯值:

x = putStrLn "x" >> return 42
y = putStrLn "y" >> return 1337

这两个值的类型都是 Num a => IO a . IO aSemigroup a 时的实例是:
instance Semigroup a => Semigroup (IO a)
-- Defined in `Data.Orphans'

这意味着可以合并两个 IO (First a)值(value)观:
Prelude Data.Semigroup Data.Orphans> fmap First x <> fmap First y
x
y
First {getFirst = 42}

但是,正如我们所见, xy产生它们各自的副作用,即使 y从来不需要。

这同样适用于 Data.Monoid :
Prelude Data.Monoid> fmap (First . Just) x <> fmap (First . Just) y
x
y
First {getFirst = Just 42}

我想我理解为什么会发生这种情况,因为 SemigroupMonoid实例使用 liftA2 ,这似乎最终基于 IO绑定(bind),这是严格的,据我所知。

如果我放弃 First抽象,但是,我可以得到更懒惰的评估:
first x _ = x

mfirst x y = do
x' <- x
case x' of
(Just _) -> return x'
Nothing -> y

使用这两个忽略 y :
Prelude> first x y
x
42
Prelude> mfirst (fmap Just x) (fmap Just y)
x
Just 42

在这两种情况下, y不打印。

那么我的问题是:

我可以两全其美吗?有没有一种方法可以保留 Semigroup 或 Monoid 抽象,同时仍然获得惰性 IO?

例如,是否有某种 LazyIO我可以包装的容器 First值,以便我得到我想要的惰性 IO?

我所追求的实际情况是,我想查询 IO 资源的优先列表以获取数据,并使用第一个给我有用响应的列表。但是,我不想执行冗余查询(出于性能原因)。

最佳答案

Alternative MaybeT 的实例monad 转换器返回第一个成功的结果,并且不执行其余的操作。结合 asum 函数,我们可以这样写:

import Data.Foldable (asum)
import Control.Applicative
import Control.Monad.Trans.Maybe

action :: Char -> IO Char
action c = putChar c *> return c

main :: IO ()
main = do
result <- runMaybeT $ asum $ [ empty
, MaybeT $ action 'x' *> return Nothing
, liftIO $ action 'v'
, liftIO $ action 'z'
]
print result

哪里最后 action 'z'不会被执行。

我们也可以用 Monoid 编写一个新类型的包装器。模仿 Alternative 的实例:
newtype FirstIO a = FirstIO (MaybeT IO a)

firstIO :: IO (Maybe a) -> FirstIO a
firstIO ioma = FirstIO (MaybeT ioma)

getFirstIO :: FirstIO a -> IO (Maybe a)
getFirstIO (FirstIO (MaybeT ioma)) = ioma

instance Monoid (FirstIO a) where
mempty = FirstIO empty
FirstIO m1 `mappend` FirstIO m2 = FirstIO $ m1 <|> m2
Alternative之间的关系和 Monoidthis other SO question 中有解释.

关于haskell - 在 append 下保持 IO 惰性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47120384/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com