我也是机器初学者,这是我的结果:
import Control.Monad
import Data.Char (intToDigit)
import Data.Machine
import Data.Machine.Plan
import Data.Machine.Source
-- | Produces integers from a list.
m1 :: [Int] -> Source Int
m1 = source
-- | Produces characters from a list.
m2 :: [Char] -> Source Char
m2 = source
-- | Reads a number from its left input. Then reads this many
-- characters from its right input. Outputs the resulting string,
-- together with the number of strings produced so far.
m3 :: Tee Int Char (Int, String)
m3 = construct (loop 0)
where
-- `loop` keeps internal state - the count of strings
-- produced so far.
loop count = do
-- Read a number from L.
n <- awaits L
-- Read this many characters from L.
s <- replicateM n (awaits R)
let count' = count + 1
-- Output the result.
yield (count', s)
loop count'
main = print . run $ tee (m1 [2,3,4,5])
(m2 "Lorem ipsum dolor sit amet") m3
我没有在 中使用过幺半群m3
,而是使用纯数字,但想法是一样的。我也使用Tee
了代替Wye
,因为我的示例需要确定性输入 - 它选择是否从L
or读取R
。但是Wye
用于类似的目的是一样的。
更新:当然可以使用State
而不是Identity
跟踪计数。例如:
m3State :: TeeT (State Int) Int Char (Int, String)
m3State = repeatedly $ do
n <- awaits L
s <- replicateM n (awaits R)
lift (modify (+ 1)) -- increment the counter
count <- lift get -- get the counter to output it
yield (count, s)
main = print . flip evalState 0 . runT $ input m3State
我怀疑repeatedly
在计划上使用比使用显式单子循环要快一些,但我认为在这个小例子中差异可以忽略不计。
或者,如果我们只想计算字符串的数量并仅在最后输出,我们可以Writer (Sum Int)
改用。完整代码在这里。