Quick actions

cmd+k|ctrl+k

Navigation

Languages

Capture-avoiding substitution

Snippet info

Language

Ocaml

Visibility

public

Author

rightfold

Created

2018-07-12T17:56:58Z

Updated

2018-07-12T19:14:43Z

module String_map = Map.Make (String)

type term =
    | Global of string
    | Local of string
    | Function of string * term
    | Application of term * term

let rec pretty : term -> string = function
    | Global name ->
        "@" ^ name

    | Local name ->
        "$" ^ name

    | Function (parameter, body) ->
        let body' = pretty body in
        "fun $" ^ parameter ^ " is " ^ body' ^ " end"

    | Application (function_, argument) ->
        let function_' = pretty function_ in
        let argument'  = pretty argument  in
        function_' ^ "(" ^ argument' ^ ")"

let next_fresh_variable = ref 0
let fresh_variable () =
    let variable = !next_fresh_variable in
    let _ = next_fresh_variable := variable + 1 in
    "%" ^ string_of_int variable

let rec substitute (work : term String_map.t) : term -> term = function
    | Global name ->
        Global name

    | Local name ->
        begin
            try String_map.find name work with
            | Not_found -> Local name
        end

    | Function (parameter, body) ->
        let fresh = fresh_variable () in
        let work' = String_map.add parameter (Local fresh) work in
        let body' = substitute work' body in
        Function (fresh, body')

    | Application (function_, argument) ->
        let function_' = substitute work function_ in
        let argument'  = substitute work argument  in
        Application (function_', argument')

let rec beta_reduce : term -> term = function
    | Global name ->
        Global name

    | Local name ->
        Local name

    | Function (parameter, body) ->
        let body' = beta_reduce body in
        Function (parameter, body')

    | Application (function_, argument) ->
        begin
            let function_' = beta_reduce function_ in
            let argument'  = beta_reduce argument  in
            match function_' with
            | Function (parameter, body) ->
                let work = String_map.singleton parameter argument in
                substitute work body
            | _ ->
                Application (function_', argument')
        end

let () =
    let term = Application (Function ("x", Application (Local "x", Local "y")), Local "y") in
    let _ = print_endline (pretty term) in
    let _ = print_endline (pretty (substitute (String_map.singleton "y" (Local "x")) term)) in
    let _ = print_endline (pretty (beta_reduce term)) in
    ()
INFO