# Correcting a Widespread Error in Unification Algorithms

## Peter Norvig

## Sandy Vanderbleek

Data Scientist, Publicis Media

sandy.vanderbleek@publicismedia.com

hiring data engineers/data scientists/web developers 🙏

twitter.com/haskellandchill

## Approach

- Establish notation
- Define problem
- Identify error and correct result
- Analyze error and correct algorithm

(a b c)

p'

p''

p?

{p => q, r => s}

{}[p => q]

{}[p]

{}/p

a \in b

pattern

first

rest

check single

substitution

update

lookup

apply

element

### Notation

## Examples

(a) \in {(a) => (b)} == true

(a) \in (a b) == true

(a b c)' == (a)

(a b c)'' == (b c)

(a)? == true

{a => b}/(a) == (b)

(a) \in {} == false

(a) \in (b c) == false

(a)' == (a)

(a)'' == ()

()' == ()

()'' == ()

(a b)? == false

()? == false

{a => b}/(c) == (c)

## Problem

unify a b == s

unify a b == fail

.:. s/a == s/b

.:. ~E s | s/a == s/b

unify (a) (a) == {}

unify (a) (b) == {a => b}

unify (a a) (a) == fail

unify (a) (b b) == {a => b b}

- Typically many answers possible, most general unifier can generate them
- Wikipedia page is a good overview

Syntactic Unification

## Error

unify (x y) (y x) == fail

Present in algorithm in several popular textbooks including Norvig's (twice) and SICP

Caused by failing to dereference bindings

## Correct

unify (x y) (y x) == {(x) => (y)}

{x => y}/(x y) == (y y)

{x => y}/(y x) == (y y)

## Wrong

unify p q s =

p == q -> s

p? -> variable p q s

q? -> variable q p s

_ -> unify p'' q'' (unify p' q' s)

variable a p s =

a \in s -> unify s[a] p s

a \in s[p] -> fail

_ -> s[a => p]

## Correct

unify p q s =

p == q -> s

p? -> variable p q s

q? -> variable q p s

_ -> unify p'' q'' (unify p' q' s)

variable a p s =

a \in s -> unify s[a] p s

** p \in s -> unify a s[p] s**

a \in s[p] -> fail

_ -> s[a => p]

## Evaluation

unify (y) (x) (unify (x) (y) {})

**by** _ -> unify p'' q'' (unify p' q' s)

**as** unify (y) (x) (unify (y) (x))

unify (y) (x) {x => y}

**by** p? -> variable p q s

**as** (y)? -> variable (y) (x) {}

**by** _ -> s[a => p]

**as** _ -> {}[y => x]

fail

**by** a \in s[p] -> fail

**as** (y) \in {x => y}[x] -> fail

Error 😱

## Evaluation

...

unify (y) (y) {x => y}

**by** p \in s -> unify a s[p] s

**as **(x) \in {x => y} -> unify (y) {x => y}[x] {x => y}

{(x) => (y)}

**by** p == q -> s

**as** (y) == (y) -> {x => y}

Correct 😇

## Norving's Hot Take

Functional Programming advocates have claimed that assignment (to a variable or data structure) is dangerous because it violates referential transparency. Curiously, this note shows that for unification, the

functional approachis error-prone, while theprocedural, state-modification approachtends to lead to a correct solution.

🔥

## Serious Next Day Thread

They all failed to either

test the resulting codesufficiently or attempt even an informalproof of correctness. Either approach could have uncovered the bug that has remained hidden until now.

✅

## Future Work

A proof of correctness for unification in Athena

in my talk "Athena: An Educational Language For Proofs In Computer Science"

to be delivered in Boulder June 4th 2018 and put online... someday 🙃

http://proofcentral.org/athena/

Fundamental Proof Methods in Computer Science