不确定 Prolog 示例,但我会在 Haskell 中通过以下方式定义它:
{-# LANGUAGE MultiParamTypeClasses, EmptyDataDecls, FlexibleInstances,
FlexibleContexts, UndecidableInstances, TypeFamilies, ScopedTypeVariables #-}
data Z
data S a
type One = S Z
type Two = S One
type Three = S Two
type Four = S Three
class Plus x y r
instance (r ~ a) => Plus Z a r
instance (Plus a b p, r ~ S p) => Plus (S a) b r
p1 = undefined :: (Plus Two Three r) => r
class Mult x y r
instance (r ~ Z) => Mult Z a r
instance (Mult a b m, Plus m b r) => Mult (S a) b r
m1 = undefined :: (Mult Two Four r) => r
class Fac x r
instance (r ~ One) => Fac Z r
instance (Fac n r1, Mult (S n) r1 r) => Fac (S n) r
f1 = undefined :: (Fac Three r) => r
class Pow x y r
instance (r ~ One) => Pow x Z r
instance (r ~ Z) => Pow Z y r
instance (Pow x y z, Mult z x r) => Pow x (S y) r
pw1 = undefined :: (Pow Two Four r) => r
-- Handy output
class (Num n) => ToNum a n where
toNum :: a -> n
instance (Num n) => ToNum Z n where
toNum _ = 0
instance (ToNum a n) => ToNum (S a) n where
toNum _ = 1 + toNum (undefined :: a)
main = print $ (toNum p1, toNum m1, toNum f1, toNum pw1)
更新:
正如 danportin 在下面的 TypeFamilies “懒惰模式”(在实例上下文中)的评论中指出的那样,这里不需要(他的初始代码更短且更清晰)。
不过,在这个问题的上下文中,我可以想到这种模式的一个应用:假设我们想将布尔逻辑添加到我们的类型级算术中:
data HTrue
data HFalse
-- Will not compile
class And x y r | x y -> r
instance And HTrue HTrue HTrue
instance And a b HFalse -- we do not what to enumerate all the combination here - they all HFalse
但是由于“功能依赖冲突”,这不会编译。在我看来,我们仍然可以在没有资金的情况下表达这种重叠的情况:
class And x y r
instance (r ~ HTrue) => And HTrue HTrue r
instance (r ~ HFalse) => And a b r
b1 = undefined :: And HTrue HTrue r => r -- HTrue
b2 = undefined :: And HTrue HFalse r => r -- HFalse
这绝对不是最好的方式(它需要 IncoherentInstances)。所以也许有人可以提出另一种不那么“创伤”的方法。