Может ли кто-нибудь предоставить машине реализацию следующего плана?
Я играю с модулем "Машины" Эдварда Кметта, и я немного запутался здесь и там. Я подумал, что лучший способ задать вопрос - предоставить вариант использования игрушки. Описано ниже.
Машины один и два сидят на двух зубцах Уай.
Машина 1 принимает в качестве параметра список целых и выталкивает его вниз по течению. Машина два принимает в качестве параметра список символов и выталкивает его вниз по течению.
Машина три сохраняет внутреннее состояние, начиная с mempty
, затем mappends
элементы, которые он получает от любой машины из базы Уай при некоторых условиях (поэтому не оба). Машина три затем получает текущее состояние и толкает его вниз.
Машина четыре печатает элементы, которые она получает, чтобы утешить.
Пока у меня есть это:
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
1 ответ
Я также начинающий с машинами, вот мой результат:
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
или же 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)
вместо. Полный код здесь.