Implementing an Idris Monad from "Scratch"

I implemented the Idris Monad Interface by hand because I didn’t see a better way.


img

First one needs a “type” to hold our data. This just needs to be generic, so I’m using Mo a

data Mo: Type -> Type where
	Free: a -> Mo a

This isn’t very interesting - I’m reluctant to say it, but, it’s just a “box” for a piece of data.

To me a Monad one must implement “bind” with is done via the >>= operator. The >>= operator takes a “chunk” of logic that computes a (new) box’ed value (Mo b) from the existing value (a in Mo a) and returns a Mo b that will be that value. This is also useful for representing effects in purely functional programs. I care because it’s needed for the do-notation which implicitly uses it to separate stuff around the a <- b.

To make Mo a an implementation of``Monad` we can implement it like this …

Monad Mo where
	-- (>>=): Mo a -> (f: a -> Mo b) -> Mo b
	(>>=) (Free a) f = f a

… where a is a value, and f would be f: a -> Mo b.

You’ll get an error stating that …

Can’t find implementation for Applicative Mo

… because Monad extends Applicative and one needs an implementation of Applicative.

… and Functor but that just looks like this …

Functor Mo where
	-- map: (a -> b) -> Mo a -> Mo b
	map f (Free a) = Free $ f a

… and gives you another way to bind. Applicative needs pure to create an instance and <*> to invoke a function in one instance on a value from another instance.

Applicative Mo where

	-- pure: a -> Mo a
	pure a = Free a

	-- (<*>): Mo (a -> b) -> Mo a -> Mo b
	(<*>) (Free f) (Free a) = Free (f a)

The implementations need to be in the specific order Functor, Applicative, Monad.

Finished

We now have something that looks like this …


data Mo: Type -> Type where
	Free: a -> Mo a

Functor Mo where
	-- map: (a -> b) -> Mo a -> Mo b
	map f (Free a) = Free $ f a

Applicative Mo where

	-- pure: a -> Mo a
	pure a = Free a

	-- (<*>): Mo (a -> b) -> Mo a -> Mo b
	(<*>) (Free f) (Free a) = Free (f a)

Monad Mo where
	-- (>>=): Mo a -> (f: a -> Mo b) -> Mo b
	(>>=) (Free a) f = f a

… and we can simplify it …


data Mo: Type -> Type where
	Free: a -> Mo a

Functor Mo where
	map f (Free a) = Free $ f a

Applicative Mo where
	pure = Free
	(Free f) <*> (Free a) = Free $ f a

Monad Mo where
	(>>=) (Free a) f = f a

… and that’s all I feel like saying for now.

comments powered by Disqus
Peter LaValle avatar
Peter LaValle
Any links probably include affiliate ids for that sweet sweet kickback - and some programs require that I tell you. The contents of this blog are likely unrelated - as they include games, paints, and build tools.