我是index-core
包的作者,答案是可以的。这是解决方案:
{-# LANGUAGE TypeOperators, RankNTypes #-}
import Control.Category.Index
import Control.IMonad
import Data.Functor.Identity
newtype ICont f a i = ICont { runICont :: (a :-> f) -> f i }
请注意,我使用f
而不是r
. s将r
成为索引。
IFunctor
和的实现IMonad
与普通 monad 的实现相同(就像博客文章的版本一样):
instance IFunctor (ICont f) where
fmapI f m = bindI (returnI . f) m
instance IMonad (ICont f) where
returnI a = ICont $ \k -> k a
bindI f m = ICont $ \k -> runICont m $ \a -> runICont (f a) k
诀窍是意识到它会减少到您在博客文章中看到的版本f = Identity
(a -> r2) -> r1
~ (a -> Identity r2) -> Identity r1
~ ((a := r2) r2 -> Identity r2) -> Identity r1
~ ((a := r2) :-> Identity) -> Identity r1
~ ICont Identity (a := r2) r1
~ R ICont Identity r1 r2 a
唯一的区别是额外R
和Identity
噪音,如果您选择匹配博客文章的版本,您可以将其抽象掉:
type ICont' r1 r2 a = ICont Identity (a := r2) r1
这是使用编写的函数的示例ICont
-- example ~ (String -> Int) -> Char
-- example ~ ((String := Int) Int -> Identity Int) -> Identity Char
example :: ICont' Char Int String
example = ICont $ \k -> Identity $
case runIdentity (k (V "Hello")) of
0 -> 'A'
_ -> 'B'
该index-core
图书馆的灵感来自 Conor McBride 的论文:Kleisli Arrows of Outrageous Fortune。请注意,Conor 的方法比博客文章中的方法需要更多的详细信息,但它提供了博客文章中没有的额外功能,主要是能够在索引中存储更强大的信息,从而提供更大的灵活性。
这对您来说意味着,如果您不需要那些额外的功能,那么您可能应该使用您在博客文章中看到的那个。但是,无论您选择什么,我都强烈建议您阅读 Conor 的论文,因为它是一篇非常出色的论文,并展示了 Haskell 类型系统的强大功能。
我没有index-core
为 . 如果您想查看使用的具体代码index-core
,只需查看我用来实现带索引的免费 monad 转换器2.2.0
的包的版本。但是,我不再使用该类型,尽管我仍然维护包。pipes
index-core
index-core
如果您还有其他问题,请随时提问!