Utils Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
module Util = struct                                                          
                                                                              
  type (α,β) result =                                                         
    | Ok  of α                                                                
    | Err of β                                                                
                                                                              
  let success : α  (α,β) result = λ x  Ok  x                                
  let failure : β  (α,β) result = λ x  Err x                                
                                                                              
  let fmap : (α  β)  (α,γ) result  (β,γ) result = λ f                     
    function                                                                  
    | Ok  x  Ok (f x)                                                        
    | Err e  Err   e                                                         
  let (<$>) : (α  β)  (α,γ) result  (β,γ) result = fmap                    
                                                                              
  let liftM : (α,γ) result  (α  (β,γ) result)  (β,γ) result = λ m f       
    match m with                                                              
    | Ok  x  f x                                                             
    | Err e  Err e                                                           
  let (>>=) : (α,γ) result  (α  (β,γ) result)  (β,γ) result = liftM        
                                                                              
  let compose_left : (α  β)  (β  γ)  α  γ = λ f g x  g(f x)             
  let (>>) : (α  β)  (β  γ)  α  γ = compose_left                         
                                                                              
  let safe_find : (α  bool)  α list  α option = λ f xs                    
    let rec aux = function                                                    
      | [   ]  None                                                          
      | x::xs                                                                
         if f x then                                                          
           Some x                                                             
         else                                                                 
           aux xs                                                             
    in                                                                        
    aux xs                                                                    
                                                                              
  let string_to_chars : string  char list = λ x                             
    let rec aux acc = function                                                
      | 0                  acc                                               
      | i  aux (x.[i-1] :: acc) (i-1)                                        
    in aux [] (String.length x)                                               
                                                                              
end                                                                           

Utils Code output:

module Util :
  sig
    type ('a, 'b) result = Ok of 'a | Err of 'b
    val success : 'a -> ('a, 'b) result
    val failure : 'b -> ('a, 'b) result
    val fmap : ('a -> 'b) -> ('a, 'c) result -> ('b, 'c) result
    val ( <$> ) : ('a -> 'b) -> ('a, 'c) result -> ('b, 'c) result
    val liftM : ('a, 'c) result -> ('a -> ('b, 'c) result) -> ('b, 'c) result
    val ( >>= ) :
      ('a, 'c) result -> ('a -> ('b, 'c) result) -> ('b, 'c) result
    val compose_left : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
    val ( >> ) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
    val safe_find : ('a -> bool) -> 'a list -> 'a option
    val string_to_chars : string -> char list
  end

Lambda Calculus Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
module LambdaCalculus = struct                                                
                                                                              
  open Printf                                                                 
  open Util   
                                                                              
  type error =                                                                
    | InvalidToken                                                            
    | NoClojureParse                                                          
    | InvalidParse                                                            
    | UnboundVariable                                                         
    | NoClojureEval                                                           
                                                                              
  type expr =                                                                 
    | Var of name                                                             
    | Lam of name * body                                                      
    | App of expr * expr                                                      
  and name  = char                                                            
  and body  = expr                                                            
                                                                              
  type token =                                                                
    | ParLeft                                                                 
    | ParRight                                                                
    | Lambda                                                                  
    | Dot                                                                     
    | Variable of char                                                        
                                                                              
  type env = (char * expr) list                                               
                                                                              
  let alphabet =                                                              
    [                                                                         
      'a';'b';'c';'d';'e';'f';'g';'h';'i';'j';'k';'l';'m';                    
      'n';'o';'p';'q';'r';'s';'t';'u';'v';'w';'x';'y';'z';                    
    ]                                                                         
                                                                               
  let rec tokenize : char list  (token list,error) result = function         
    | [       ]  [                                   ] |> success            
    | ' ' :: xs  tokenize xs                                                 
    | '(' :: xs  tokenize xs >>= λ ys  ParLeft  :: ys |> success            
    | ')' :: xs  tokenize xs >>= λ ys  ParRight :: ys |> success            
    | '^' :: xs  tokenize xs >>= λ ys  Lambda   :: ys |> success            
    | '.' :: xs  tokenize xs >>= λ ys  Dot      :: ys |> success            
    | var :: xs                                                              
       if   List.mem var alphabet                                             
       then tokenize xs >>= λ ys  Variable var   :: ys |> success            
       else InvalidToken                                |> failure            

  let rec parse_aux : token list  (expr * token list,error) result = function
    |           Variable var        :: xs  (Var var, xs) |> success          
    | Lambda :: Variable var :: Dot :: xs                                    
       parse_aux xs >>=                                                       
         λ (body,tokens)  (Lam (var,body), tokens)       |> success          
    | ParLeft                       :: xs                                    
       parse_aux xs >>=                                                       
         (λ (func,ys)                                                        
           parse_aux ys >>=                                                   
             (λ (value,zs)                                                   
               match zs with                                                  
               | ParRight :: tokens  (App (func,value), tokens) |> success   
               | __________________  NoClojureParse             |> failure   
             )                                                                
         )                                                                    
    | _________________________________  InvalidParse           |> failure   
  let parse : token list  (expr,error) result = λ xs                        
    fst <$> parse_aux xs                                                      
                                                                              
  let rec eval_aux : env  expr  (env * expr,error) result = λ env          
    function                                                                  
    | Var var                                                                
       let result =                                                           
         match safe_find (λ (v,t)  var = v) env with                         
         | Some (_,expr)  ([],expr)                 |> success               
         | None           UnboundVariable           |> failure               
       in result                                                              
    | Lam (var, body)                                                        
       (env, Lam (var, body))                        |> success               
    | App (func, value)                                                      
       eval_aux env func >>= function                                         
       | closed_env, Lam (var, body)                                         
          eval_aux env value >>= λ (_,eval_value)                            
          eval_aux ((var,eval_value) :: closed_env) body                      
       | ___________________________  NoClojureEval |> failure               
  let eval : expr  (expr,error) result = λ xs                               
    snd <$> eval_aux [] xs                                                    

  let rec pretty_printer : expr  (string,error) result = function            
    | Var var                                                                
       sprintf "%c"     var   |> success                                      
    | Lam (var,body)                                                         
       pretty_printer body >>= λ x                                           
       sprintf "^%c.%s" var x |> success                                      
    | App (func,value)                                                       
       pretty_printer func  >>= λ x                                          
       pretty_printer value >>= λ y                                          
       sprintf "(%s %s)" x y  |> success                                      
                                                                              
  let interpret : string  (string,error) result = λ x                       
    string_to_chars x |> success                                              
    >>= tokenize                                                              
    >>= parse                                                                 
    >>= eval                                                                  
    >>= pretty_printer                                                        
                                                                              
end                                                                           

Lambda Calculus Code output:

module LambdaCalculus :
  sig
    type error =
        InvalidToken
      | NoClojureParse
      | InvalidParse
      | UnboundVariable
      | NoClojureEval
    type expr = Var of name | Lam of name * body | App of expr * expr
    and name = char
    and body = expr
    type token = ParLeft | ParRight | Lambda | Dot | Variable of char
    type env = (char * expr) list
    val alphabet : char list
    val tokenize : char list -> (token list, error) Util.result
    val parse_aux : token list -> (body * token list, error) Util.result
    val parse : token list -> (expr, error) Util.result
    val eval_aux : env -> body -> (env * expr, error) Util.result
    val eval : expr -> (expr, error) Util.result
    val pretty_printer : body -> (string, error) Util.result
    val interpret : string -> (string, error) Util.result
  end

Assertions Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module AssertLambdaCalculus = struct                                          
                                                                              
  open Util                                                                   
                                                                              
  let simple : bool =                                                         
    LambdaCalculus.interpret "^x.x" =                                         
      Ok "^x.x"                                                               
                                                                              
  let complex : bool =                                                        
    LambdaCalculus.interpret "((^x.^y.x ^a.(a a)) ^b.b)" =                    
      Ok "^a.(a a)"                                                           
                                                                              
  (* let omega : bool =                                                       
    LambdaCalculus.interpret "(^x.(x x) ^x.(x x))" =                          
      Ok "Infinte loop, never terminates" *)                                  
                                                                              
end

Assertions Code output:

module AssertLambdaCalculus : 
  sig 
    val simple  : bool 
    val complex : bool 
  end

AssertLambdaCalculus.simple;;
- : bool = true
AssertLambdaCalculus.complex;;
- : bool = true

References:

  • Michael Gilliland, Let’s Write a Lambda Calculus in F# video series: