相互递归的IO定义

Cli*_*ton 2 haskell

我可以写下面的内容:

f :: [Int] -> [Int]
f x = 0:(map (+1) x)

g :: [Int] -> [Int]
g x = map (*2) x

a = f b
b = g a

main = print $ take 5 a
Run Code Online (Sandbox Code Playgroud)

事情完美无缺(想象).

但是,假设我想做g一些比2乘以更复杂的事情,比如向用户询问一个数字并添加它,如下所示:

g2 :: [Int] -> IO [Int]
g2 = mapM (\x -> getLine >>= (return . (+x) . read))
Run Code Online (Sandbox Code Playgroud)

那我怎么打结呢?

澄清:

基本上我希望Ints 的列表f是输入g2,Ints 的列表g2是输入f.

Gab*_*lez 11

列表的有效推广是ListT:

import Control.Monad
import Pipes

f :: ListT IO Int -> ListT IO Int
f x = return 0 `mplus` fmap (+ 1) x

g2 :: ListT IO Int -> ListT IO Int
g2 x = do
    n  <- x
    n' <- lift (fmap read getLine)
    return (n' + n)

a = f b
b = g2 a

main = runListT $ do
    n <- a
    lift (print n)
    mzero
Run Code Online (Sandbox Code Playgroud)

您还可以take使用一些额外的代码实现类似的功能:

import qualified Pipes.Prelude as Pipes

take' :: Monad m => Int -> ListT m a -> ListT m a
take' n l = Select (enumerate l >-> Pipes.take n)

main = runListT $ do
    n <- take' 5 a
    lift (print n)
    mzero
Run Code Online (Sandbox Code Playgroud)

示例会话:

>>> main
0
1<Enter>
2
2<Enter>
3<Enter>
7
4<Enter>
5<Enter>
6<Enter>
18
7<Enter>
8<Enter>
9<Enter>
10<Enter>
38
Run Code Online (Sandbox Code Playgroud)

您可以ListT通过阅读pipes教程,特别是有关ListT部分了解更多信息.