2016-12-26 12 views
3

У меня есть эта простая "стрелка":Неожиданный результат Когда Monoid на Arrows прикладываются

main = do 
     let 
     -- arr :: (Arrow a) => (b -> c) -> a b c 
     -- (>>>) :: Category cat => cat a b -> cat b c -> cat a c 
     -- (<+>) :: ArrowPlus a => a b c -> a b c -> a b c 
     -- infixr 5 <+> 
     -- infixr 1 >>> 
     -- runKleisli :: Kleisli m a b -> a -> m b 
      prepend x = arr (x ++) 
      append x = arr (++ x) 

      xform = (prepend "<") >>> (append ">") <+> (prepend "{") >>> (append "}") 
      xs = ["foobar"] >>= (runKleisli xform) 
     mapM_ putStrLn xs 

В <+> возвращается:

<foobar>} 
{<foobar} 

и если я заменить xform с:

xform = ((prepend "<") >>> (append ">")) <+> ((prepend "{") >>> (append "}")) 

Получаю:

<foobar> 
{foobar} 

Почему я получаю эти 2 результата? Даже глядя на infixr s (как комментарии в коде) на самом деле не помогает.

+0

[Это, вероятно, даст вам решение] (http://stackoverflow.com/questions/40331179/how-to-automatically-parenthesize-arbitrary-haskell-expressions). – Alec

ответ

4

Позволяет написать, что немного больше к точке:

xform = prepend "<" >>> append ">" <+> prepend "<" >>> append ">" 
xform' = (prepend "<" >>> append ">") <+> (prepend "<" >>> append ">") 

Теперь xform, потому что infixr 5 <+> связывает более плотно, чем infixl 1 >>>, анализируется как

xform = prepend "<" >>> (append ">" <+> prepend "<") >>> append ">" 

, который, как это схема считывает

      ┌─append ">"──┐ 
    ──────prepend "<"─────<    +>═══append ">"═════▶ 
          └─prepend "<"─┘ 

тогда как xform' соответствует просто

  ┌─prepend "<"──append ">"─┐ 
    ───────<       +>════▶ 
      └─prepend "<"──append ">"─┘ 

Это должно объяснить это.

+0

Спасибо! Очень ясно (и ваши графики потрясающие;)) – Randomize

4

Неясно, из вашего вопроса, что вы ожидали от этого. Если этот ответ по-прежнему не поможет, написание того, что вы ожидаете от своего кода, поможет нам понять, как вы думаете.

Стрелка, с которой вы работаете, - Kleisli [] - то есть стрелка, построенная из списка монада. Список как монада - абстракция недетерминированности - то есть списки ведут себя как совокупности возможностей.

Тип Kliesli [] a b эквивалентен a -> [b], рассматриваемый как монадическая функция, то есть: он принимает один вход и возвращает много возможных выходов.

То, что <+> делает, преобразует входные данные каждым из своих аргументов, а затем берет объединение возможностей. Так что если вы запустите стрелку:

arr id <+> arr reverse 

с входом "hello", то вы получите два ответа:

hello 
olleh 

Если вы составляете его с чем-либо, каждая возможность будет состоять:

prepend "<" >>> (arr id <+> arr reverse) 

, то вы получите

<hello 
olleh< 

, поэтому каждая альтернатива <+> рассматривается «параллельно».Причина, по которой < подходит к второй строке, состоит в том, что вход arr reverse уже получил "<". В противоположность этому, если вы сделали

(arr id <+> arr reverse) >>> prepend "<" 

Тогда вы получите

<hello 
<olleh 

Является ли это делание смысл, почему вы получите вывод, который вы сделали сейчас?

+0

Спасибо за ваш ответ, который очень ясен. Графики @leftaroundabout также прояснили слишком много. – Randomize