[英]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.