The mappy package

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.



Please see

[Skip to ReadMe]


Change logNone available
Dependenciesansi-terminal, base (>=4.7 && <5), containers, directory, haskeline, mappy, parsec [details]
Copyright2015 Michael Gilliland
AuthorMichael Gilliland
Home page
Source repositoryhead: git clone
UploadedThu Feb 18 00:05:52 UTC 2016 by mjgpy3




Maintainers' corner

For package maintainers and hackage trustees

Readme for mappy-


Build Status Hackage Actively Maintained

A functional programming language. Like LISP but focused around maps rather than lists.


To install, use cabal

cabal install mappy

Installing from source

To build install from source, use stack

stack install

this will install the mappy executable. The exact location may vary, on my machine, this installs to ~/.local/bin.


mappy has a REPL that is activated by running mappy with no arguments.

Running a mappy program

To run a mappy program, simple run the executable, giving it the path of a mappy source file (ensure it has a main function defined). For example, to run the prelude, run

mappy prelude/

Hello, world

main = [give :print "Hello, World" io]


For less contrived examples, see the prelude.


Keywords are names in mappy that always evaluate to themselves. Keywords begin with : and can have a wide range of values, for example, the following are keywords

Keywords are primarily useful for naming things, like keys in a map.


The primary value in mappy is the map (a la Hash in Ruby, HashMap in Java, etc...). To define a map, surround key value pairs with parenthesis.


The empty map


A map containing maps

  :type :person,
  :job (
    :title :hacker-pro,
    :salary :infinity

Note that, like in Clojure, commas are parsed as whitespace in mappy.


Lists are really just a special form of maps. Because of this, there's another sugar to handle them using the (| and |) delimiters. For, example here's a list of some keywords

(|:a :b :c :d :e|)


Characters are a special form of maps (noticing a pattern here?). As in other languages, characters are surrounded by single quotes



Strings are lists of characters. As in other languages, they are surrounded by double quotes

"I am a nice string!\nHave a good day :)"


For less contrived examples, see the prelude.

Binding values

mappy doesn't really have variables. Instead, you can bind names to values

answer = :forty-two

this binds the name answer to the keyword :forty-two.

Binding functions

You can also define functions that operate on values

first a b = a

this creates a function named first that takes two arguments and returns the first one.

Functions can have lazy arguments

Let expressions

mappy has ML-esque let expressions. For example, here's how filter is defined

filter p? xs = [
  if [empty? xs]
      first = [take :head xs]
      rest = [take :tail xs]
      [if [p? first]
       [cons first [filter p? rest]]
       [filter p? rest]

Note that let expressions are just syntactic sugar over nested lambdas.

Applying functions

To apply functions, use square brackets, e.g.

the-first-value = [first :a :b]

this applies the first function, defined above, to :a and :b and binds the name the-first-value to the result.

Partial application

In mappy, functions are automatically partially applied if too few arguments are given. This feature, is well aligned with functional programming because it allows us to easily build new functions from existing ones.

For example, suppose we wanted to build a function that adds two to a number. We might do so like thus

add-two num = [add two num]

This is pretty nice, but in mappy it can get more elegantly

add-two = [add two]


In mappy, IO is done using the special io map, using the core primitives.


To print a value, use give

[give :print "Hi, from mappy!" io]

Writing a file

To write a file, use give

[give :write-file (:text "File content", :file "out.txt") io]

Reading a file

To read a file, use take

[take (:read-file "") io]

Lambda functions

To create a lambda function the syntax \arg1 arg2 argN -> body is used, where argX are the argument names and body is an expression. So, if we wanted to define our first function above, using lambdas, it would look like

first = \a b -> a

Lazy arguments

Note that lambdas can have "lazy-arguments" (by wrapping in parenthesis), for example, here's how if is defined in mappy

if cond (then) (else) = [[
  default-take [take :truthy cond] (:false else) then

the [[ and ]] are not special, they are normal function application. In this case, they apply default-take then the result (either else or then).

Core primitives

Like LISP, mappy is built around a small set of core primitives. mappy's core primitives are called give, take and default-take. Being as mappy is built around maps, all core primitives operate on maps.


Returns a new map with a new association. If the given key existed in the map before, then it will be overwritten in the returned copy.


[give :foo :bar (:baz :quux)]

returns: (:baz :quux :foo :bar)


Attempts to retrieve a value from a map. If the value is not present, an error will occur.


[take :foo (:foo :bar)]

returns: :bar

More simply, applying a keyword to a map is the same as applying take. For example, the above example can be rewritten as

[:foo (:foo :bar)]


Like take except, instead of erring, it returns a default value if the key is not found.


[default-take :foo (:baz :quux) :bar]

returns: :bar