This elixir package gives an implementation of higher order logic via the simply typed lambda calculus and higher order pre-unification. All lambda terms are always automatically beta-reduced and eta-expanded. Bound Variables are automatically named via de bruijn indices.

This package was developed at University of Bamberg with the AISE Chair.

Installation

This package can be installed by adding hol to your list of dependencies in mix.exs:

def deps do
  [
    {:hol, "1.0.1"}
  ]
end

Documentation

Documentation is available on hexdocs

Most important functions

Unification Examples

The following and more examples can be found interactively in the livebook.

Setup for Tests:

type_i = mk_type(:i)
type_ii = mk_type(type_i, [type_i])
type_ii_ii = mk_type(type_ii, [type_ii])
type_iii = mk_type(type_i, [type_i, type_i])

Example: x * 10 = 1000

t_x = mk_free_var_term("x", type_ii_ii)

x_times_10 = mult_term() |> mk_appl_term(t_x) |> mk_appl_term(mk_num(10))

input = [
  {x_times_10, mk_num(1000)}
]

result = unify(input, true, 1000)
pp_res(result, true)

This finds one substitution that replaces x with the church numeral 100

x = 100: x <- (2 1. 2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 (2 1) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

Example: xaa = faa

t_x = mk_free_var_term("x", type_iii)
t_a = mk_const_term("a", type_i)
t_f = mk_const_term("f", type_iii)

xaa = mk_appl_term(mk_appl_term(t_x, t_a), t_a)
faa = mk_appl_term(mk_appl_term(t_f, t_a), t_a)

input = {xaa, faa}

result = unify(input)
pp_res(result)

Finds nine possible substitutions for unification:

x <- λ 2 1. f 1 1

x <- λ 2 1. f 1 2

x <- λ 2 1. f 1 a

x <- λ 2 1. f 2 1

x <- λ 2 1. f 2 2

x <- λ 2 1. f 2 a

x <- λ 2 1. f a 1

x <- λ 2 1. f a 2

x <- λ 2 1. f a a

Example: x(fa) = f(xa)

t_x = mk_free_var_term("x", type_ii)
t_f = mk_const_term("f", type_ii)
t_a = mk_const_term("a", type_i)

xfa = mk_appl_term(t_x, mk_appl_term(t_f, t_a))
fxa = mk_appl_term(t_f, mk_appl_term(t_x, t_a))

depth = 5
input = {xfa, fxa}

result = unify(input, true, depth)
pp_res(result)

This finds four solutions:

x <- λ 1. 1

x <- λ 1. f 1

x <- λ 1. f (f 1)

x <- λ 1. f (f (f 1))

However the maximum search depth was also reached twice. This means that it might not have found all solutions. Try changing the depth value and see what other solutions can be found!

Example: Multiple Equations

  • xy+z=21
  • x+y+z=10
  • xz+y=9
t_x = mk_free_var_term("x", type_ii_ii)
t_y = mk_free_var_term("y", type_ii_ii)
t_z = mk_free_var_term("z", type_ii_ii)

input = [
  {plus(mult(t_x, t_y), t_z), mk_num(21)},
  {plus(plus(t_x, t_y), t_z), mk_num(10)},
  {plus(mult(t_x, t_z), t_y), mk_num(9)}
]

depth = 50
result = unify(input, true, depth)
pp_res(result, true)

Two Solutions are found here:

z = 1, y = 4, x = 5: z <- λ 2 1. 2 1 | y <- λ 2 1. 2 (2 (2 (2 1))) | x <- λ 2 1. 2 (2 (2 (2 (2 1))))

z = 1, y = 5, x = 4: z <- λ 2 1. 2 1 | y <- λ 2 1. 2 (2 (2 (2 (2 1)))) | x <- λ 2 1. 2 (2 (2 (2 1)))

Once again the maximum search depth was reached multiple times. However increasing the search depth will not yield more solutions here. Unification doesn't always terminate even when no more solutions can be found!