我是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
。 r
將成爲指數。
的IFunctor
和IMonad
實現等同於普通的單子(就像博客文章的版本)的實現:
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
庫編寫一個函數是由科納·麥克布賴德的論文的啓發的例子:Kleisli Arrows of Outrageous Fortune。請注意,Conor的方法需要比博客文章更多的冗長性,但它提供了博客文章中沒有的額外功能,主要是能夠在索引中存儲更強大的信息,從而提供更大的靈活性。
這對你來說意味着如果你不需要那些額外的功能,那麼你應該使用你在博客文章中看到的那個。不過,我強烈建議你閱讀Conor的論文,不管你選擇什麼,因爲它是一篇非常出色的論文,並且顯示了Haskell的類型系統有多強大。
我沒有爲index-core
實現任何索引monads,主要是因爲我編寫了該庫來爲我寫的另一個庫搔癢。如果你想查看使用index-core
具體的代碼,只是檢查出pipes
包我曾經index-core
實現索引免費單子轉換的2.2.0
版本。不過,我不再使用該類型的任何更長的時間,但我還是保持index-core
包。
如果您有任何其他疑問,歡迎提問!
另請參見類似的問題:http://stackoverflow.com/questions/23887237/how-to-implement-index-core-style-indexed-state-monad –