我正在關注Conor McBride的「Kleisli憤怒的財富箭頭」論文,並且我發佈了他的代碼here的實現。簡要地說,他定義了以下類型和類:索引單子的重新綁定符號
type a :-> b = forall i . a i -> b i
class IFunctor f where imap :: (a :-> b) -> (f a :-> f b)
class (IFunctor m) => IMonad m where
skip :: a :-> m a
bind :: (a :-> m b) -> (m a :-> m b)
data (a := i) j where
V :: a -> (a := i) i
然後他定義了兩種類型結合的,其中後者的使用(:=)
限制初始索引:
-- Conor McBride's "demonic bind"
(?>=) :: (IMonad m) => m a i -> (a :-> m b) -> m b i
(?>=) = flip bind
-- Conor McBride's "angelic bind"
(>>=) :: (IMonad m) => m (a := j) i -> (a -> m b j) -> m b i
m >>= f = bind (\(V a) -> f a) m
後者綁定工作完全正常重新編號do
表示法使用帶有RebindableSyntax
擴展名的索引單子,使用return
和fail
的以下相應定義:
return :: (IMonad m) => a -> m (a := i) i
return = skip . V
fail :: String -> m a i
fail = error
...但問題是,我不能得到前綁定(即(?>=)
)工作。我試着而不是定義(>>=)
和return
是:
(>>=) :: (IMonad m) => m a i -> (a :-> m b) -> m b i
(>>=) = (?>=)
return :: (IMonad m) => a :-> m a
return = skip
然後創建保證居住在特定的索引數據類型:
data Unit a where
Unit :: Unit()
但是當我嘗試使用新的定義重新綁定do
符號(>>=)
和return
,它不起作用,如以下示例所示:
-- Without do notation
test1 = skip Unit >>= \Unit -> skip Unit
-- With do notation
test2 = do
Unit <- skip Unit
skip Unit
test1
型檢查,但test2
沒有,這是奇怪的,因爲我覺得所有的RebindableSyntax
所做的就是讓do
符號desugar test2
到test1
,所以如果test1
類型的檢查,那麼爲什麼不test2
?我得到的錯誤是:當我使用顯式forall
語法而不是:->
型運營商的
Couldn't match expected type `t0 -> t1'
with actual type `a0 :-> m0 b0'
Expected type: m0 a0 i0 -> (t0 -> t1) -> m Unit()
Actual type: m0 a0 i0 -> (a0 :-> m0 b0) -> m0 b0 i0
In a stmt of a 'do' block: Unit <- skip Unit
In the expression:
do { Unit <- skip Unit;
skip Unit }
錯誤甚至仍然存在。
現在我知道使用「惡魔綁定」還有一個問題,那就是你無法定義(>>)
,但我仍然想看看我能走多遠。任何人都可以解釋爲什麼我不能讓GHC去解除「惡魔般的束縛」,即使它通常會進行類型檢查?
因爲這出現在一個[較新的重複問題](http://stackoverflow.com/questions/33488322/ranknpolymorphism-and-kleisli-arrows-of-outrageous-fortune),我會指出,現在的GHC (目前爲7.10.2)幾乎完全支持'ImpredicativeTypes',所以現在比這個代碼的'do'符號要多得多。 –