gpt4 book ai didi

Haskell 的类型系统和逻辑编程——如何将 Prolog 程序移植到类型级别

转载 作者:行者123 更新时间:2023-12-03 10:43:07 26 4
gpt4 key购买 nike

我试图理解逻辑编程语言(在我的例子中是 Prolog)和 Haskell 的类型系统之间的关系。

我知道根据关系使用统一和变量来查找值(或类型,在 Haskell 的类型系统中)。为了更好地理解它们之间的异同,我尝试在 Haskell 的类型级别重写一些简单的 prolog 程序,但是我在某些部分遇到了麻烦。

首先,我重写了这个简单的 prolog 程序:

numeral(0).
numeral(succ(X)) :- numeral(X).

add(0,Y,Y).
add(succ(X),Y,succ(Z)) :- add(X,Y,Z).

作为:
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

它工作正常,但我无法用这个 Prolog 扩展它:
greater_than(succ(_),0).
greater_than(succ(X),succ(Y)) :- greater_than(X,Y).

我尝试的是这样的:
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

此代码的问题是最后两个实例导致fundep 冲突。我能理解为什么,但在我看来这应该不是问题,因为它们的保护部分(或者不管它叫什么,我的意思是 (Greaterthan a b c) => 部分)是不同的,所以 a s 和 b最后两个实例声明中的 s 实际上是不同的值,并且没有冲突。

我试图重写的另一个程序是:
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).

(顺便说一句,示例来自 Learn Prolog Now 书)
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

我在最后一行收到“重复实例”错误。我认为这是一个类似的问题,即使我有不同的防护部件,我也会遇到错误,因为 body 部件(我的意思是 Descend a b 部件)是相同的。

因此,如果可能的话,我正在寻找将 Prolog 程序移植到 Haskell 类型级别的方法。任何帮助将不胜感激。

编辑:

Ed'ka 的解决方案有效,但方式完全不同。我仍在尝试了解我们何时可以在类型系统中运行 Prolog 程序,何时/为什么我们需要编写不同的算法以使其工作(如在 Ed'ka 的解决方案中),以及何时/为什么没有办法在 Haskell 的类型系统中实现一个程序。

也许我可以在阅读“Fun With Functional Dependencies”之后找到一些关于此的提示。

最佳答案

作为@ stephen tetley已经指出,当 GHC 尝试匹配实例声明时,它只考虑实例头部(=> 之后的东西)完全忽略实例上下文(=> 之前的东西),一旦找到明确的实例,它就会尝试匹配实例上下文。您的第一个有问题的示例显然在实例头中有重复,但可以通过用一个更通用的实例替换两个冲突的实例来轻松修复它:

instance (Greaterthan a b r)  => Greaterthan (Succ a) (Succ b) r

第二个例子虽然困难得多。我怀疑要让它在 Haskell 中工作,我们需要一个类型级别的函数,它可以根据特定实例是否为 产生两种不同的结果。定义与否对于特定类型的参数(即,如果有一个实例 Child Name1 Name2 - 递归地用 Name2 做某事,否则返回 BFalse )。我不确定是否可以使用 GHC 类型对此进行编码(我怀疑不是)。

但是,我可以提出一个适用于稍微不同类型的输入的“解决方案”:而不是暗示不存在 parent->child关系(当没有为此类对定义实例时)我们可以使用类型级列表显式编码所有现有关系。然后我们可以定义 Descend类型级函数,虽然它必须依赖令人生畏的 OverlappingInstances扩大:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies,
FlexibleInstances, FlexibleContexts, TypeOperators,
UndecidableInstances, OverlappingInstances #-}

data Anne
data Bridget
data Caroline
data Donna
data Emily
data Fred
data George

-- Type-level list
data Nil
infixr 5 :::
data x ::: xs

-- `bs` are children of `a`
class Children a bs | a -> bs

instance Children Anne (Bridget ::: Nil)
instance Children Bridget (Caroline ::: Donna ::: Nil)
instance Children Caroline (Emily ::: Nil)
-- Note that we have to specify children list for everyone
-- (`Nil` instead of missing instance declaration)
instance Children Donna Nil
instance Children Emily Nil
instance Children Fred (George ::: Nil)
instance Children George Nil

-- `or` operation for type-level booleans
class OR a b bool | a b -> bool
instance OR BTrue b BTrue
instance OR BFalse BTrue BTrue
instance OR BFalse BFalse BFalse

-- Is `a` a descendant of `b`?
class Descend a b bool | a b -> bool
instance (Children b cs, PathExists cs a r) => Descend a b r

-- auxiliary function which checks if there is a transitive relation
-- to `to` using all possible paths passing `children`
class PathExists children to bool | children to -> bool

instance PathExists Nil a BFalse
instance PathExists (c ::: cs) c BTrue
instance (PathExists cs a r1, Children c cs1, PathExists cs1 a r2, OR r1 r2 r)
=> PathExists (c ::: cs) a r

-- Some tests
instance Show BTrue where
show _ = "BTrue"

instance Show BFalse where
show _ = "BFalse"

t1 :: Descend Donna Anne r => r
t1 = undefined -- outputs `BTrue`

t2 :: Descend Fred Anne r => r
t2 = undefined -- outputs `BFalse`
OverlappingInstances因为 PathExists 的第 2 次和第 3 次实例,这里是必需的都可以匹配 children 时的情况不是空列表,但在我们的例子中,GHC 可以确定更具体的列表,具体取决于列表的头部是否等于 to参数(如果是,则意味着我们找到了路径,即后代)。

关于Haskell 的类型系统和逻辑编程——如何将 Prolog 程序移植到类型级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13899586/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com