

(pipe (lift x) f) = (f x)

(pipe m lift) = m

(pipe (pipe m f) g) = (pipe m (lambda (x) (pipe (f x) g)))





class Monad m where

return :: a -> m a

(>>=) :: m a -> (a -> m b) -> m b





instance Monad [ ] where

(x:xs) >>= f = f x ++ (xs >>= f)

[] >>= f = []

return x = [x]





(define bind

[] _ -> []

[X | Xs] F -> (append (F X) (bind Xs F)))



(define return

X -> [X] )





(2-) (bind [10 20 30] (/. X [ X (+ X 1) ] ) )

[10 11 20 21 30 31]





(5-) (define f X -> [ X (+ X 1) ] )

f



(6-) (bind (return 2) f)

[2 3]



(7-) (f 2)

[2 3]





(8-) (bind [ 4 5 6] return)

[4 5 6]





(9-) (define g X -> [ (+ X 33) (+ X 44) ] )

g



(10-) (bind (bind [10 20 30] f) g)

[43 54 44 55 53 64 54 65 63 74 64 75]



(11-) (bind [10 20 30] (/. X (bind (f X) g)))

[43 54 44 55 53 64 54 65 63 74 64 75]





(14-) (bind [10 20 a] (/. X (bind (f X) g)))

1+: a is not a NUMBER





(datatype monad



X : (list A);

=====

[X] : (monad list A);



)





(define list_monad

{ (list A) --> (monad list A) }

X -> [X] )



(define m_head

{ (monad list A) --> A }

X -> (head (get_list X)))



(define m_tail

{ (monad list A) --> (monad list A) }

X -> [ (tail (get_list X))] )



(define m_cons

{ A --> (monad list A) --> (monad list A) }

X [Xs]-> [(cons X Xs)])



(define join

{ (monad list (monad list A)) --> (monad list A)}

Xs -> (join-help [[]] Xs))



(define join-help

{ (monad list A) --> (monad list (monad list A)) --> (monad list A) }

Final [[]] -> [ (reverse (get_list Final)) ]

Final ML -> (let XRest (m_tail (m_head ML))

(if (= XRest [[]])

(join-help (m_cons (m_head (m_head ML)) Final)

(m_tail ML))

(join-help (m_cons (m_head (m_head ML)) Final)

(m_cons (m_tail (m_head ML)) (m_tail ML))) )))





(define bind

{ (monad list A) --> ( A --> (monad list B)) --> (monad list B) }

XS F -> (join [(map F (get_list XS)) ]))



(define return

{ A --> (monad list A) }

X -> [[X]]

)





(14+) (bind (list_monad [10 20 30]) (/. X (list_monad [X (+ X 1)]) ))

[[10 11 20 21 30 31]] : (monad list number)





(31+) (head (bind (list_monad [4 5 6]) return))

error: type error





(36+) (define f

{ symbol --> (monad list symbol) }

X -> (list_monad [ x o x]) where (= X x)

_ -> (list_monad [ o o o]))





(37+) (bind (return x) f)

[[x o x]] : (monad list symbol)



(38+) (bind (bind (return x) f) f)

[[x o x o o o x o x]] : (monad list symbol)



(39+) (bind (bind (bind (return x) f) f) f)

[[x o x o o o x o x o o o o o o o o o x o x o o o x o x]] : (monad list symbol)



9 Comments:

It is hard to even begin to learn the cutting edge of functional language theory these days without talking about monads. In languages running in a purely functional manner, monads offer a way of dealing with the outside environment in a safe and controlled manner. In a pure environment, monads provide us a way to carry data computations via pure functional composition and still have computations that happen "on the side." A lot of research into functional languages requires a solid understanding of monads and thus to apply their results to the Qi programming language, I'll define a few monad operations here and define a type theory that can handle the list monadSince you can find a wide variety of monads for the language Haskell, I will start by describing monads in Haskell and use that to define representations inside of the Qi language. Basically, a monad is a type that defines two operations. The operations are "lift" and "pipe". In Haskell, they are often called "return" and "bind" respectively. As long at the two functions hold the following identities, we can consider the type to be a monad.Here is a definition of the rules a monad must follow in a pure version of scheme.In Haskell, the Monad m class is defined byWe can see that return "lifts" a value of type a into the monad class m a. Bind takes in a monad of type "a" and a function that takes in a value of type "a" and gives a monad of type "b". Bind then returns to us a monad of type "b" where the monad "a" has been transformed by the function into a monad of type "b". Once we have these two functions working as defined, we have a monad. Notice that we have not defined these functions yet. Haskell allows us to define a higher order type that we promise that all implementations of the type will have the listed functions and they will match the given type signatures. These sorts of definitions are not as easy in Qi, yet.One of the basic monad types in Haskell is the list monad. We define list monads as having type Monad [] and we can make a set of functions that follow the monad laws over Monad []'s.Let us rewrite these rules in Qi.Well that was easy! Let us try out this new monad... We'll take a list of [10 20 30] and a function that takes an X and returns [X X+1] and give it to bind to see what it does with it.So far, so good. Let us check the monad laws to see if this version follows those laws. Law 1 says that (bind (return X) F) == (F X)Law 2 says (bind Monad return) == MonadLaw 3 says that (bind (bind Monad F) G) = (bind Monad (/. X (pipe (F X) G)))So we have proven that our monad list does in fact honor the monad laws. However, we are not running the type checker in Qi on this problem, so the monad we get is the same one that we can get in any functional language. We have to wait until runtime to see the error of the following attempt at using a monad.So now the question becomes, can we get a monad into the TYPED version of Qi. Firstly, we must note that Qi has no notion of polymorphic type overloading. Hence we cannot easily make a general purpose "bind" operator that all monads can use. We also should note that the type checker treats a polymorphic list as a special case, and thus we cannot perform a direct translation like the one from Haskell. In some way, we will have to contain our lists in another type.Let us take the simplest translation. If something is of type (list A) then we can make a monadic list type of (monad list A) via the following sequent rules.Monadic lists are simply lists inside of a container list and any list in a container can be a monad list of that type. We should read this as saying, "We can construct monads from lists by adding a list around it and we can construct lists from monads." We note that Qi allows you to go back from a monadic representation to the list based one as long as you properly use the type. Unfortunately, Qi has no notion of modules so we cannot seal off this behaviour from other functions in our code.Continuing, we will define some helper functions to allow us to manipulate the monad data structure inside the instance functions. Of course, Qi has no notion of either class or instance and allows us to pull lists from monads. But if we ignore these quirks for the moment, we can define a reasonable monad list type that works. I include a constructor function "list_monad" and a few internal data access helpers.Our m_ functions and join properly deal with getting (list A)'s from their containers and putting them back in. Join has to take the job of flatten and check for the end of a list and if we find it, drop it from the "Final" list. This accounts for the if statement in the function. It obviously makes heavy use of the data manipulation functions which lowers legability. We can read it as saying, "Take the first element head of the list (remember that we have a monad list of a monad lists here) and put it on the final list. Then take the rest of that head list and put it back on the processing queue. The Final output list is built in reverse order so we are forced to reverse the computation at the end of the join. Not pretty, but it works for the purpose of monad construction.Now we are in a position to define "bind" and "return" as before.Note that we basically take the list out of the monad container and apply normal list functions to it, wrapping it up back in the monad container when we return.Testing it out gives:And our monad type is certainly not a listNow let us assure ourselves that our monad list is polymorphic to type A. We now define a fractal symbol function f.And let us use it with our monad functionsSo there you have it, a very simple, poorly performing basic list monad of polymorphic type A in the Qi Programming Language. Feel free to offer any questions or criticism that you have. Thanks for reading.

Post a Comment