operational/
lib.rs

1//! The operational library makes it easy to implement monads with tricky control flow.
2//!
3//! This is very useful for: writing web applications in a sequential style,
4//! programming games with a uniform interface for human and AI players and easy replay,
5//! implementing fast parser monads, designing monadic DSLs, etc.
6//!
7//! A thorough introduction to the ideas behind this library is given in
8//! ["The Operational Monad Tutorial"](http://apfelmus.nfshost.com/articles/operational-monad.html),
9//! published in [Issue 15 of the Monad.Reader](http://themonadreader.wordpress.com/2010/01/26/issue-15/).
10
11use std::fmt;
12
13/// Contains the `Instr` trait, and a few useful utilities for working with instructions.
14pub mod instr;
15use instr::Instr;
16
17mod kleisli;
18pub use kleisli::Kleisli;
19
20mod seq;
21pub use seq::*;
22
23/// Represents a program, i.e. a sequence of instructions.
24///
25/// - The _instructions_ are given by the type `I`.
26/// - `A` is the return type of the program.
27pub enum Program<'a, I: Instr, A> {
28    /// The case `Pure(a)` means that the program contains no instructions and just returns the result `a`.
29    Pure(Box<A>),
30    /// The case `Then(instr, k)` means that the first instruction is `instr` and the remaining program is given by the kleisli arrow `k`.
31    Then(Box<I>, Kleisli<'a, I, I::Return, A>)
32}
33
34impl<'a, I: 'a + Instr, A> Program<'a, I, A> {
35
36    fn and_then_boxed<B, F>(self, js: F) -> Program<'a, I, B>
37        where F: 'a + Fn(Box<A>) -> Program<'a, I, B> {
38        match self {
39            Program::Pure(a) => js(a),
40            Program::Then(i, is) => Program::Then(i, kleisli::append_boxed(is, js))
41        }
42    }
43
44    /// Appends a continuation to a program. Which means,
45    /// given a function from `A` to `Program<I, B>`,
46    /// passes the return value of the program to the function,
47    /// and returns the resulting program.
48    ///
49    /// Equivalent to the monadic `>>=` operator.
50    pub fn and_then<B, F>(self, js: F) -> Program<'a, I, B>
51        where F: 'a + Fn(A) -> Program<'a, I, B> {
52        match self {
53            Program::Pure(a) => js(*a),
54            Program::Then(i, is) => Program::Then(i, is.append(js))
55        }
56    }
57
58    /// Modifies the return value of the program.
59    /// Seen differently, it lifts a function from
60    /// `A` to `B` into a function from `Program<I, A>`
61    /// to `Program<I, B>`.
62    ///
63    /// Equivalent to the monadic `liftM`.
64    pub fn map<B, F>(self, f: F) -> Program<'a, I, B>
65        where F: 'a + Fn(A) -> B {
66        self.and_then(move |a| point(f(a)))
67    }
68
69}
70
71impl<'a, I: 'a + Instr, A: PartialEq> PartialEq for Program<'a, I, A> {
72    fn eq(&self, other: &Program<'a, I, A>) -> bool {
73        match (self, other) {
74            (&Program::Pure(ref a), &Program::Pure(ref b)) => a == b,
75            _ => false
76        }
77    }
78}
79
80impl<'a, I: 'a + Instr, A: fmt::Debug> fmt::Debug for Program<'a, I, A> {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        match self {
83            &Program::Pure(ref a) => write!(f, "Pure({:?})", a),
84            &Program::Then(_, _) => write!(f, "Then(..)")
85        }
86    }
87}
88
89/// Using a value, constructs the empty program,
90/// i.e. a program that directly returns that value.
91///
92/// Equivalent to the monadic `return`.
93pub fn point<'a, I: 'a + Instr, A>(a: A) -> Program<'a, I, A> {
94    Program::Pure(Box::new(a))
95}