I'm trying to understand the relation between a logic programming language(Prolog in my case) and Haskell's type system.
I know both use unification and variables to find values(or types, in Haskell's type system) depending on relations. As an exercise to understand similarities and differences between them better, I tried to rewrite some simple prolog programs in Haskell's type level, but I'm having trouble with some parts.
First, I rewrote this simple prolog program:
numeral(0).
numeral(succ(X)) :- numeral(X).
add(0,Y,Y).
add(succ(X),Y,succ(Z)) :- add(X,Y,Z).
as:
class Numeral a where
numeral :: a
numeral = u
data Zero
data Succ a
instance Numeral Zero
instance (Numeral a) => Numeral (Succ a)
class (Numeral a, Numeral b, Numeral c) => Add a b c | b c -> a where
add :: b -> c -> a
add = u
instance (Numeral a) => Add a Zero a
instance (Add x y z) => Add (Succ x) (Succ y) z
it works fine, but I couldn't extend it with this Prolog:
greater_than(succ(_),0).
greater_than(succ(X),succ(Y)) :- greater_than(X,Y).
What I tried was this:
class Boolean a
data BTrue
data BFalse
instance Boolean BTrue
instance Boolean BFalse
class (Numeral a, Numeral b, Boolean r) => Greaterthan a b r | a b -> r where
greaterthan :: a -> b -> r
greaterthan = u
instance Greaterthan Zero Zero BFalse
instance (Numeral a) => Greaterthan (Succ a) Zero BTrue
instance (Numeral a) => Greaterthan Zero (Succ a) BFalse
instance (Greaterthan a b BTrue) => Greaterthan (Succ a) (Succ b) BTrue
instance (Greaterthan a b BFalse) => Greaterthan (Succ a) (Succ b) BFalse
The problem with this code is that last two instances are causing fundep conflict. I can understand why, but it seems to me that it shouldn't be a problem since their guard parts(or whatever it's called it, I mean the (Greaterthan a b c) =>
part) are different, so that a
s and b
s in last two insance declarations are actually different values and there are no conflicts.
Another program I tried to rewrite was this:
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
child(donna,emily).
descend(X,Y) :- child(X,Y).
descend(X,Y) :- child(X,Z),
descend(Z,Y).
(btw, examples are from Learn Prolog Now book)
data Anne
data Bridget
data Caroline
data Donna
data Emily
class Child a b | a -> b where
child :: a -> b
child = u
instance Child Anne Bridget
instance Child Bridget Caroline
instance Child Caroline Donna
instance Child Donna Emily
class Descend a b | b -> a where
descend :: b -> a
descend = u
instance (Child a b) => Descend a b
instance (Child a c, Descend c b) => Descend a b
And I'm getting "duplicate instances" error in last line. I think it's a similar problem, even if I have a different guard parts, I'm getting errors because body parts(I mean Descend a b
parts) are the same.
So I'm looking for ways to port that Prolog programs to Haskell's type level, if possible. Any help will be appreciated.
EDIT:
Ed'ka's solution works but in a completely different way. I'm still trying to understand when we can run a Prolog program in type-system, when/why we need to write a different algorithm to make it work(like in Ed'ka's solution), and when/why there's no way to implemenet a program in Haskell's type-system.
Maybe I can find some pointers about this after reading "Fun With Functional Dependencies".