我正在玩Edward Kmett的机器模块,我在这里和那里都有点困惑。我认为问一个问题的最好方法是提供一个玩具用例。如下所述。
机器一和二坐在两个叉子的叉子上。
机器1将整数列表作为参数,然后将其推送到下游。 机器2将字符列表作为参数,并将其推送到下游。
机器3保持内部状态,从mempty
开始,然后mappends
在某些条件下从Wye基础上从任一台机器接收的元素(因此不是两者)。机器3然后获得当前状态并推动它下降。
Machine 4将收到的元素打印到控制台。
到目前为止,我已经得到了这个:
y1 :: PlanT k [Int] m ()
y1 = yield
y2 :: PlanT k [Char] m ()
y2 = yield
但我不确定如何组合y1和y2;或者滚动隐藏状态的任意进程,而不是使用Process.hs导出的某个库存组合器。
根据建议,指向机器包的链接: http://hackage.haskell.org/package/machines
pdf提供了非常高级别的描述:https://dl.dropboxusercontent.com/u/4588997/Machines.pdf
答案 0 :(得分:5)
我也是机器的初学者,这是我的结果:
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
中使用过monoid,我使用的是普通数字,但这个想法是一样的。我还使用Tee
代替Wye
,因为我的示例需要确定性输入 - 它选择是从L
还是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
比使用明确的monadic循环要快一些,但我认为在这个小例子中差异可以忽略不计。
或者,如果我们只想计算字符串的数量并仅在结尾输出,我们可以使用Writer (Sum Int)
代替。完整代码here。