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".
-XTypeFamilies
but I'm not sure how much. Interesting question – PendantDataKinds
language extension creates a kind for any defined ADT with types in that kind for each of the ADT's constructors, which you can reference using theKindSignatures
extension. In this case, you therefore don't need classes and instances forNumeral
andBoolean
as you can use kinds instead.data Numeral=Zero|Succ Numeral
and then your class declaration forAdd
becomesclass Add (a :: Numeral) (b :: Numeral) (c :: Numeral) | a b -> c
and so on. You actual don't needBoolean
at all then, as you can usePrelude.Bool
– Kimsey