Haskell - 如何避免与IO混淆纯粹

Rah*_*hul 1 algorithm monads haskell io-monad

我正在haskell上实现一些算法.该算法需要生成一些数据.

我有一个算法的功能,它将生成函数作为参数.例如,算法只是将输入数据乘以n:

 algo :: a -> ??? -> [a]
 algo n dgf = map (\x -> x * n) $ dgf
Run Code Online (Sandbox Code Playgroud)

dgf用于生成数据.如何正确编写函数头,dgf可以是任何具有任意数量参数的函数?

另一种变体是不接受生成函数但已经生成数据.

algo :: a -> [b] -> [a]
algo n d = (\x -> n*x) d
Run Code Online (Sandbox Code Playgroud)

那么,现在让我们想象一下我stdGen使用IO 生成数据.如何使函数更通用,以便它可以同时接受IO实例和普通值[1,2,3].这也涉及具有功能的变体,因为它也可以产生IO.

总而言之,哪种解决方案更好 - 具有生成功能或预生成数据?

提前致谢.

dfe*_*uer 6

一种选择是采用而不是列表.如果生成值涉及执行IO,并且可能有许多值,这通常是最好的方法.有几个包提供某种类型的流,但我将streaming在此示例中使用该包.

import qualified Streaming.Prelude as S
import Streaming

algo :: Monad m => a -> Stream (Of a) m r -> Stream (Of a) m r
algo a = S.map (a +)
Run Code Online (Sandbox Code Playgroud)

您可以将其Stream (Of a) m r视为"使用操作m生成类型的连续值a并最终生成类型结果的方法r".此algo函数不承诺生成数据的任何特定方式; 它们可以纯粹创建:

algo a (S.each [these, are, my, elements])
Run Code Online (Sandbox Code Playgroud)

或内IO,

algo a $ S.takeWhile (> 3) (S.readLn :: Stream (Of Int) IO ())
Run Code Online (Sandbox Code Playgroud)

或使用随机monad,或任何你喜欢的.