簡體   English   中英

關於lambda表達式中傳遞給monad的參數,可以證明什么?

[英]What can be proved about parameters in lambda expressions, passed into monads?

相對於魚類經營者,Monads滿足關聯性。

(h >=> g) >=> f = h >=> ( g >=> f)

轉換為綁定(使用lambda表達式)后的樣子,

\a -> h a >>=(\b -> g b >>= \c -> f c) = 
\a ->(h a >>= \b -> g b)>>= \c -> f c

這意味着以下等式是明確的

( a -> h a >>= \b -> g b >>= \c -> f c ) =  h >=> g >=> f

這是了解Monadic組成的好方法。

但是,並非所有Monadic代碼都將綁定變量與lambda分開。 例如,

[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch) = 
[(1,'a'),(1,'b'),(2,'a'),(2,'b')]

返回值中的“ n”是從頂部lambda獲得的。

更普遍,

a -> g a >>= \b -> f a b

f取決於上面的a和b。 根據f,g和(> =>)定義以上內容

\a -> (\x -> g a) >=> f a 

我不太了解。 它與我很好地顯示的上述方程式不匹配。 我認為魚是這里的基本概念,並且我試圖理解魚與我編寫的典型Monads的相互作用。 我想更好地理解以上內容。

解決此問題的一種方法是嘗試從List表達式語法獲取含義

[ (n,ch) | n <- [1, 2], ch <- ['a', 'b'] ]

我認為這暗示着一種對稱。

連接lambda表達式和Monad是否有任何好的對稱性? 還是我對此讀得太多? 我擔心高度嵌套的lambda表達式是錯誤的還是合理的?

不,沒有任何限制。 綁定lambda后,您可以執行任何操作 這是Applicative 之所以Monad Monad的原因之一, 因為它較弱 (因此為您提供了更強的自由定理限制)。

 ( [1,2] >>= \n -> "ab" >>= \ch -> return (n,ch) )
   ≡  (,) <$> [1,2] <*> "ab"
   ≡  liftA2 (,) [1,2] "ab"
   ≈  liftA2 (flip (,)) "ab" [1,2]

最后一個實際上不是一個適當的方程式。 僅適用法律 確保這些表達式的相同 請參閱注釋 ,但結構可能會有所不同。

Prelude Control.Applicative> liftA2 (,) [1,2] "ab"
[(1,'a'),(1,'b'),(2,'a'),(2,'b')]
Prelude Control.Applicative> liftA2 (flip (,)) "ab" [1,2]
[(1,'a'),(2,'a'),(1,'b'),(2,'b')]

解決您的編輯問題,在其中考慮如何編寫...

 \\a -> ga >>= \\b -> fab 

...使用(>=>) ,在這種情況下實際上沒有丟失。 退后一步,仔細考慮如何將(>=>)轉換為(>>=) ,反之亦然:

f >=> g = \x -> f x >>= g
m >>= f = (const m >=> f) () -- const x = \_ -> x

在與您的問題相關的第二個方程式中,我們將(>>=)的第一個參數轉換為一個函數,可以使用const將其傳遞給(>=>) 由於const m >=> f是一個忽略其參數的函數,我們只需將()作為偽參數傳遞即可恢復(>>=)

這樣,您的示例可以使用第二個公式重寫:

\a -> g a >>= \b -> f a b
\a -> (const (g a) >=> \b -> f a b) ()
\a -> (const (g a) >=> f a) ()

除了提供虛擬()技巧外,這是您在問題中獲得的。

您的問題的另一個想法:從效果可以取決於輸入的意義上講,單聲道是最通用的。 取輸入a並產生輸出b的單子計算m可以寫成a -> mb 由於這是一個函數,我們(可以)使用lambda定義此類計算,它可以自然地向右擴展。 但是,這種普遍性會使您\\a -> ga >>= \\b -> fab分析計算復雜化。

對於箭頭 (占據應用函子和單子之間的空間),情況有所不同。 對於常規箭頭,輸入必須是顯式的-箭頭計算arr具有arr ab的常規類型。 因此,必須使用Arrow原語將在箭頭計算中跨越“正向”的輸入顯式地線程化到那里。

擴大你的榜樣

{-# LANGUAGE Arrows #-}

import Control.Arrow

bind2 :: (Monad m) => (a -> m b) -> (a -> b -> m c) -> a -> m c
bind2 g f = \a -> g a >>= \b -> f a b

到箭頭:函數f現在必須以一對作為輸入(因為箭頭定義為接受一個輸入值)。 使用箭頭do記號,我們可以將它表示為

bind2A :: (Arrow arr) => arr a b -> arr (a, b) c -> arr a c
bind2A g f = proc a -> do
                b <- g -< a
                c <- f -< (a, b)
                returnA -< c

或更簡單地使用Arrow原語:

bind2A' :: (Arrow arr) => arr a b -> arr (a, b) c -> arr a c
bind2A' g f = (returnA &&& g) >>> f

圖形化:

--------------->[   ]
   \            [ f ]---->
    \-->[ g ]-->[   ]

不太籠統,箭頭允許在實際執行電路之前推斷出有關電路的更多信息。 理解箭頭一本不錯的書,它描述了其背后的原始動機-構建解析器,該解析器可以通過具有靜態和動態部分來避免空間泄漏。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM