Может ли кто-нибудь предоставить машине реализацию следующего плана?

Я играю с модулем "Машины" Эдварда Кметта, и я немного запутался здесь и там. Я подумал, что лучший способ задать вопрос - предоставить вариант использования игрушки. Описано ниже.

Машины один и два сидят на двух зубцах Уай.

Машина 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) вместо. Полный код здесь.

Другие вопросы по тегам