我正在做函式式編程課程的一項作業,發現在理解 Haskell 中的 monad 時遇到了一些問題。
所以,我們得到了一個型別:
data Annotated e a = a :# e
infix 0 :#
任務是用給定的型別簽名實作一些函式,我做到了。他們通過了所需的測驗(單獨):
mapAnnotated :: (a -> b) -> (Annotated e a -> Annotated e b)
mapAnnotated f (x :# w) = f x :# w
joinAnnotated :: Semigroup e => Annotated e (Annotated e a) -> Annotated e a
joinAnnotated ((b :# m) :# n) = b :# m <> n
distAnnotated :: Semigroup e => (Annotated e a, Annotated e b) -> Annotated e (a, b)
distAnnotated (x :# m, y :# n) = (x, y) :# m <> n
但是,我們還被要求滿足以下等式:
distAnnotated (p, q) = joinAnnotated (mapAnnotated (\a -> mapAnnotated (\b -> (a, b)) q) p)
我無法完全理解這么多功能應用程式,因此對于具有類似任務的其他型別,我只是做了看起來“自然”的事情并且它有效,但在這里它沒有,我不明白為什么,因為我不甚至看不到實作這些功能的其他方法。我錯過了什么?
uj5u.com熱心網友回復:
讓我們從麻煩的等式開始,系統地替換定義,從內到外進行處理:
-- Given
mapAnnotated f (x :# w) = f x :# w
joinAnnotated ((b :# m) :# n) = b :# m <> n
distAnnotated (x :# m, y :# n) = (x, y) :# m <> n
p = x :# m
q = y :# n
-- Goal
distAnnotated (p, q) = joinAnnotated (mapAnnotated (\a -> mapAnnotated (\b -> (a, b)) q) p)
-- Right-hand side
joinAnnotated (mapAnnotated (\a -> mapAnnotated (\b -> (a, b)) q) p)
joinAnnotated (mapAnnotated (\a -> mapAnnotated (\b -> (a, b)) (y :# n)) (x :# m))
joinAnnotated (mapAnnotated (\a -> (\b -> (a, b)) y :# n) (x :# m))
joinAnnotated (mapAnnotated (\a -> (a, y) :# n) (x :# m))
joinAnnotated (mapAnnotated (\a -> (a, y) :# n) (x :# m))
joinAnnotated ((\a -> (a, y) :# n) x :# m)
joinAnnotated (((x, y) :# n) :# m)
(x, y) :# n <> m
-- Left-hand side
distAnnotated (p, q)
distAnnotated (x :# m, y :# n)
(x, y) :# m <> n
-- LHS /= RHS
因此,問題distAnnotated在于以與joinAnnotated( m <> nvs n <> m)不同的順序組合注釋。使他們達成一致的通常方法是進行更改,joinAnnotated以便首先使用外部注釋:
joinAnnotated ((b :# m) :# n) = b :# n <> m
這既符合 monadic bind ( m >>= f = joinAnnotated (mapAnnotated f m))中計算的自然順序 ( ) 和應用效果 ( p <*> q = ap p q = mapAnnotated (\(f, a) -> f a) (distAnnotated (p, q)))的傳統從左到右的順序。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/363864.html
