How to implement index-core style indexed continuation monad

岁酱吖の 提交于 2019-12-03 13:17:21

I'm the author of the index-core package, and the answer is that you can. Here's the solution:

{-# 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 }

Note that I use f instead of r. The rs are going to be the indices.

The implementation of IFunctor and IMonad are identical to the implementation of the ordinary monad (just like the blog post's versions):

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

The trick is to realize that it reduces to the version you saw in the blog post when 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

The only difference is the extra R and Identity noise, which you can abstract away if you choose to match the blog post's version:

type ICont' r1 r2 a = ICont Identity (a := r2) r1

Here's an example of a function written using 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'

The index-core library was inspired by Conor McBride's paper: Kleisli Arrows of Outrageous Fortune. Note that Conor's approach requires greater verbosity than the one in the blog post, but it affords extra features that the one in the blog post does not, mainly in the ability to store more powerful information in the indices that offer even greater flexibility.

What that means for you is that if you do not need those extra features then you should probably use the one you saw in the blog post. However, I highly recommend that you read Conor's paper no matter what you choose, because it is a really excellent paper and shows how powerful Haskell's type system can be.

I didn't implement any of the indexed monads for index-core, mainly because I wrote that library to scratch an itch of mine for another library I wrote. If you want to see the concrete code that uses index-core, just check out version 2.2.0 of the pipes package where I used index-core to implement the indexed free monad transformer. However, I no longer use that type any longer, although I still maintain the index-core package.

If you have any other questions, feel free to ask!

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!