{-# LANGUAGE RankNTypes #-}
newtype C a = C {runCont :: forall r. (a -> r) -> r}
instance Functor C where
fmap f (C arr) = C $ \br -> arr $ br . f
instance Applicative C where
pure a = C ($ a)
(C abrr) <*> (C arr) = C $ \brr -> abrr ( \ab -> arr ( brr . ab ) )
instance Monad C where
-- (C arr) >>= aCbrr = C $ \br -> arr (\a -> runCont (aCbrr a) br) -- The usual
(C arr) >>= aCbrr = arr aCbrr -- My simpler idea with the same result in this test
main :: IO ()
main = print $ flip runCont id $ do
x <- pure (5::Int)
y <- pure $ 2 * x
z <- pure $ take y $ repeat 'a'
pure z
根据Noughtmare的建议,增加了一些法律证据。我认为它们直观上是有意义的,但评论的步骤可能不是正式的声音:
Left identity: pure a >>= h === h a
pure a >>= h
C (\k -> k a) >>= h
(\k -> k a) h
h a
Right identity: m >>= pure === m
m >>= pure
C arr >>= pure
arr pure
arr ( \a -> C (\k -> k a) )
C ( \k -> k (arr id) ) -- because arr knows nothing about r
C arr -- because arr::(a->r)->r so k::a->r
m
Associativity:
(m >>= f) >>= g === m >>= (\x -> f x >>= g)
((C arr) >>= f) >>= g === (C arr) >>= (\x -> f x >>= g)
(arr f) >>= g
f (arr id) >>= g
(pure.h) (arr id) >>= g === (C arr) >>= (\x -> (pure.h) x >>= g)
C (h (arr id)) >>= g === arr ( \x -> (C (h x)) >>= g )
=== C (h (arr id)) >>= g
1条答案
按热度按时间c3frrgcw1#
修改后的定义工作正常(除了我不知道如何让
flip runCont
进行类型检查--我认为您需要手动翻转参数)。然而,我也认为你会发现你的延续单子不是很有用。通常的连续单子是秩-1类型:
它很有用,因为
C' r a
与a
值“几乎同构”,除了类型r
是已知的。这意味着你可以构造一个C' Int Char
类型的一元值,表示一个纯Char
:但是你也可以构造一个相同类型的一元值
C' Int Char
,用Int
返回值来缩短计算:相比之下,你的二阶连续单子:
与
a
类型同构。同构的一个方向由pure
给出,另一个方向由下式给出:所以,用你的
C Char
,你可以表示一个纯Char
:就这样
由于这种同构,对于某些
a0 :: a
,arr
总是等于截面($ a0)
,对于某些f :: a -> b
,aCbrr
总是等于\a' -> C ($ f a')
,这意味着>>=
的原始定义如下:而您修改后的
>>=
定义给出了所以这两个定义是等价的。