Пример бесплатной расширяющей игрушки монады

Я пытаюсь расширить игрушечный пример, описанный в этом блоге. сообщение.

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}

module FreeToy where

import Control.Monad.State
import Control.Monad.Free
import Data.Map (Map)
import qualified Data.Map as M


-- defining commands
data Toy a next = 
          Output a next
        | AnnoyingOutput a (String -> next)
        | Done
        deriving (Functor)

-- lifing commands to free monad level
output :: a -> Free (Toy a) ()
output x = liftF $ Output x ()

annoyingOutput :: a -> Free (Toy a) {-some type-}
annoyingOutput x = liftF $ AnnoyingOutput x {-some function-}

done :: Free (Toy a) r
done = liftF $ Done

-- defining one of the interpreter
runToy :: (Show a, Show r) => Free (Toy a) r -> String
runToy (Free (Output a x)) =
    "output " ++ show a ++ "\n" ++ runToy x
runToy (Free (AnnoyingOutput a f)) = 
    "annoying output " ++ show a ++ runToy (f "blah blah blah \n")
runToy (Free Done) =
    "done\n"
runToy (Pure r) =
    "return " ++ show r ++ "\n"

Я попытался добавить новую вещь: AnnoyingOutput a (String -> next) это возьмет что-то и вернет строковое сообщение. Я создаю структуру, поднимая ее на уровень Free monad с помощью функции liftF. Пожалуйста, помогите мне заполнить пробелы, и правильное объяснение заметно.

Изменить: добавление примера

module Main where

import FreeToy
import Control.Monad.Free

program ::  Free (Toy String) ()

program = do
      output "something"
      x <- annoyingOutput "something else"
      output x
      done

main :: IO ()
main = putStrLn $ runToy program

person venu gangireddy    schedule 05.09.2016    source источник
comment
Можете ли вы добавить пример того, как вы хотели бы использовать эти функции?   -  person Bergi    schedule 05.09.2016
comment
Добавлен пример @Bergi, обратите внимание, что эта программа еще не скомпилирована, поэтому ожидайте некоторых ошибок   -  person venu gangireddy    schedule 05.09.2016
comment
Я не вижу в этом примере, почему или как тип надоедливого вывода будет отличаться от обычного вывода? Что вы подразумеваете под возьмет что-то и вернет строковое сообщение?   -  person Bergi    schedule 05.09.2016
comment
Я отредактировал его снова, пожалуйста, обновите вопрос   -  person venu gangireddy    schedule 05.09.2016
comment
Я подозреваю, что тип String, а функция id, но я не уверен   -  person Bergi    schedule 05.09.2016
comment
Между прочим, ваш runToy, кажется, пропустил дело Pure   -  person Bergi    schedule 05.09.2016
comment
Да, что-то не так с runToy Ошибки: 1. Не удалось сопоставить ожидаемый тип «Free (Toy a) r -> String» с фактическим типом «[Char]» 2. Не удалось сопоставить ожидаемый тип «[Char]» с фактическим type 'Free (Toy a0) r0 -> String'   -  person venu gangireddy    schedule 05.09.2016
comment
Добавлен случай @Bergi Pure, по-прежнему не удается устранить вышеуказанные ошибки. какие-либо предложения?   -  person venu gangireddy    schedule 05.09.2016
comment
Есть примеры того, как писать такие вещи, как annoyingOutput, в ответе на этот связанный вопрос. annoyingOutput будет выглядеть как add.   -  person Cirdec    schedule 05.09.2016
comment
$ в runToy $ f "blah blah blah \n" следует заменить runToy (f "blah blah blah \n")   -  person Michael    schedule 06.09.2016
comment
Тип annoyingOutput :: a -> Free (Toy a) String; annoyingOutput x = liftF $ AnnoyingOutput x id. Это означает, что правильно функция запуска должна иметь доступ к источнику строк, где вы просто продолжаете кормить его "blah blah blah \n"   -  person Michael    schedule 06.09.2016
comment
@Michael, спасибо за совет, на самом деле это очень помогло. Не могли бы вы объяснить разницу между runToy $ f "blah blah blah \n" следует заменить runToy (f "blah blah blah \n")? вообще $ и () можно заменить, почему в данном случае по другому?   -  person venu gangireddy    schedule 06.09.2016
comment
venu, это просто сверхнизкий приоритет $ мешает тому, что вы хотите, что-то вроде ... ++ ... ++ ... $ имеет infixr 0, поэтому ghc читает его как доминирующую связку в выражении, так что что-то в форме ... $ ... что тогда он может 'Т понять. Вы хотите, чтобы $ был ограничен последней добавленной вещью - вы также можете написать (runToy $ f "blah blah blah \n") для управления $, но как только вы используете круглые скобки, вы можете также поместить их вокруг (f "blah ..). Вы можете запросить приоритет в ghci с помощью :i ++ или :info $ и т.п.   -  person Michael    schedule 06.09.2016