Xeebi

home categories feeds

Haskell で IO をつなげて [a -> IO a] -> IO a 的なこと

Haskell でこういう関数が欲しいことがある:

connect :: Monad m => [a -> m a] -> a -> m a
-- 気分的には
connect (f0:f1:..) n = do
    p0 <- f0 n
    p1 <- f1 p0
    ..
    fn pn

具体的にはこういうこと

printAndMultiply :: Int -> Int -> IO Int
printAndMultiply n m = do
    print m
    return (n*m)

main = do
  n <- connect [printAndMultiply 2, printAndMultiply 3] 6
  putStrLn "______"
  print n

で出力が

6
12
______
36

とりあえず Hoogle に訊いてみよう. [a -> m a] -> a -> m a

このへんがそれっぽい?

(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)

というわけで例えばこう書くことができる

import Control.Monad
import Data.List (foldl')

printAndMultiply :: Int -> Int -> IO Int
printAndMultiply n m = do
    print m
    return (n*m)

f = printAndMultiply

fs :: [Int -> IO Int]
fs = [f 2, f 3, f 5, f 1, f 2]

connect :: (Monad m) => [a -> m a] -> a -> m a
connect = foldl' (>=>) return

main = do
    nn <- connect fs 4
    print "__"
    print nn

出力

4
8
24
120
120
"__"
240

なんだけどこれでいいのかなあ.なんかもうちょっと綺麗な書き方があるような気がするんですよね. あと Functor とか Applicative とかで上手いことできないのだろうか.このへん慣れ親しみかけているところなのでまだよくわかりません.