I am trying to follow along with this blog post to make a simple intuitionistic theorem proving language in Haskell. Mr. van Bakel suggests using indexed monads for proof state manipulation; here are the building pieces to an indexed monad (equivalent to the definitions from Control.Monad.Indexed
):
class IFunctor f where
imap :: (a -> b) -> f j k a -> f j k b
class IFunctor m => IPointed m where
ipure :: a -> m i i a
class IPointed m => IApplicative m where
iap :: m i j (a -> b) -> m j k a -> m i k b
class IApplicative m => IMonad m where
ibind :: (a -> m j k b) -> m i j a -> m i k b
ijoin :: IMonad m => m i j (m j k a) -> m i k a
ijoin = ibind id
infixr 1 =<<<
infixl 1 >>>=
(>>>=) :: IMonad m => m i j a -> (a -> m j k b) -> m i k b
m >>>= k = ibind k m
(=<<<) :: IMonad m => (a -> m j k b) -> m i j a -> m i k b
(=<<<) = ibind
I am struggling to properly instantiate these classes with the following definition of Tactic
:
data Tactic i j a = Tactic ((a -> j) -> i)
Starting with IFunctor
:
instance IFunctor Tactic where
imap f (Tactic g) = Tactic (\ h -> g (h . f))
-- f :: a -> b
-- g :: (a -> j) -> i
-- h :: b -> j
And now to make it pointed:
instance IPointed Tactic where
ipure a = Tactic (\ h -> h a)
Simple enough. I cannot wrap my head around constructing the applicative and monadic instances, however. My guess for the monad is
instance IMonad Tactic where
ibind f (Tactic g) = Tactic (\ h -> imap g (imap h . f))
-- f :: a -> Tactic ((b -> k) -> j)
-- g :: (a -> j) -> i
-- h :: b -> k
-- RHS :: Tactic ((b -> k) -> i)
since the signatures seem to check out. I am completely stumped by the applicative instance though.
instance IApplicative Tactic where
iap (Tactic f) (Tactic g) = Tactic (\ h -> ???)
-- f :: ((a -> b) -> j) -> i
-- g :: (a -> k) -> j
-- h :: b -> k
-- RHS :: Tactic ((b -> k) -> i)
What would you suggest?
Edit: I got the applicative instance to work via
instance IApplicative Tactic where
iap (Tactic f) (Tactic g) = Tactic (\ h -> f (\ x -> g (h . x)))
-- f :: ((a -> b) -> j) -> i
-- g :: (a -> k) -> j
-- h :: b -> k
-- RHS :: Tactic ((b -> k) -> i)
-- x :: a -> b, h . x :: a -> k
thanks to Li-Yao's hint on the typo in g
signature, but I am still stuck on the bind definition.
CodePudding user response:
Hints:
- There's a typo in the type of
g
in the comment (EDIT: now fixed) - What's the type of the hole
???
? (see more details below) - Another way is to implement
iap
usingimap
andibind
, the same way you can implement(<*>)
usingfmap
and(>>=)
Tactic
is a more indexed version of the continuation monadtype Cont r a = (a -> r) -> r
, so if you're familiar with that, the implementation is the same.
You can do type-driven programming by putting a hole _
and by looking at the error message from the compiler.
instance IMonad Tactic where
ibind f (Tactic g) = Tactic _
-- error: Found hole: _ :: (b -> k) -> i
When the hole has a function type, it's always safe to start with a lambda:
instance IMonad Tactic where
ibind f (Tactic g) = Tactic (\h -> _)
-- error: Found hole: _ :: i
-- Relevant bindings include
-- h :: b -> k
-- g :: (a -> j) -> i
-- f :: a -> Tactic j k b
The only way to produce an i
is to apply g
to some argument.
instance IMonad Tactic where
ibind f (Tactic g) = Tactic (\h -> g _)
-- error: Found hole: _ :: a -> j
Again a function.
instance IMonad Tactic where
ibind f (Tactic g) = Tactic (\h -> g (\a -> _))
-- error: Found hole: _ :: j
-- Relevant bindings include
-- a :: a
-- h :: b -> k
-- g :: (a -> j) -> i
-- f :: a -> Tactic j k b
There is no obvious way to produce a j
, but there is a way to use the a
which we just introduced, with f :: a -> Tactic j k b
(and upon closer inspection we see that it will in fact yield a j
eventually). We can then pattern-match on the resulting Tactic
to get some more data:
instance IMonad Tactic where
ibind f (Tactic g) = Tactic (\h -> g (\a ->
let Tactic p = f a in _))
-- error: Found hole: _ :: j
-- Relevant bindings include
-- p :: (b -> k) -> j
-- a :: a
-- h :: b -> k
-- g :: (a -> j) -> i
-- f :: a -> Tactic j k b
The final step is left as an exercise for the reader.