2016-12-26 28 views
3

我有這個簡單的 「箭」:意外的結果當上箭頭一個Monoid的應用

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 [] - 即構建在列表monad上的箭頭。作爲monad的列表是非確定性的抽象 - 也就是說,列表的行爲就像可能性的集合。

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