gpt4 book ai didi

haskell - 存在类型歧义

转载 作者:行者123 更新时间:2023-12-05 00:24:34 24 4
gpt4 key购买 nike

为这个有点人为的例子道歉。我试图在不失去理由的情况下尽可能地简化它:

假设我有一个多参数类型类 Relation :
class Relation r a b where ....
以及一个在这种类型上存在量化的函数:
neighbours :: forall r a b. Relation r a b => a -> r -> Graph -> [b]
现在我介绍几个Relation的实例。 :

data Person = Person String
data Pet = Pet String
data Owns = Owns
data Desires = Desires
instance Relation Owns Person Pet
instance Relation Desires Person Pet

现在我想编写一个方法,通过某种方式获取与给定人关联的所有宠物,而不暴露实现的复杂性:
data PetAttachment = AttachOwns | AttachDesires

personPets :: Person -> PetAttachment -> Graph -> [Pet]
personPets person att g =
neighbours person r g
where
r = case PetAttachment of
AttachOwns -> Owns
AttachDesires -> Desires

我的问题是:我如何正确输入 r .没有提示,它会尝试输入 Owns并因此失败。我也可以暗示它应该是存在类型的:
r :: forall r. Relation r Person Pet => r

但是编译器似乎无法推断出 Relation r0 Person Pet ,说 r0不明确:

relation.hs:26:5: No instance for (Relation r0 Person Pet) arising from a use of ‘neighbours’

The type variable ‘r0’ is ambiguous



我能说服吗 r以这样的方式输入,让这个编译?

完整的可编译示例:
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}

data Graph = Graph

class Relation r a b where
relation :: (r,a,b) -> Int

neighbours :: forall r a b. Relation r a b => a -> r -> Graph -> [b]
neighbours = undefined

data Person = Person String
data Pet = Pet String
data Owns = Owns
data Desires = Desires
instance Relation Owns Person Pet where
relation _ = 1
instance Relation Desires Person Pet where
relation _ = 2

data PetAttachment = AttachOwns | AttachDesires

personPets :: Person -> PetAttachment -> Graph -> [Pet]
personPets person att =
neighbours person r
where
r :: forall r. Relation r Person Pet => r
r = case att of
AttachOwns -> Owns
AttachDesires -> Desires

main :: IO ()
main = undefined

最佳答案

这里有两种编写此方法的方法,一种使用 GADT,另一种使用 Rank 2 Type。

GADT

GADT可以捕获 r 上的约束必须存在 Relation r Person Pet 的实例.要使用 GADT,您需要添加

{-# LANGUAGE GADTs #-}
RelationOf a b将捕获 Relation r a b构造函数中的实例 RelationOf由于 Relation r a b =>对构造函数的约束。
data RelationOf a b where
RelationOf :: Relation r a b => r -> RelationOf a b
personPets然后可以随心所欲地写成
personPets :: Person -> PetAttachment -> Graph -> [Pet]
personPets person att =
case r of (RelationOf r') -> neighbours person r'
where
r :: RelationOf Person Pet
r = case att of
AttachOwns -> RelationOf Owns
AttachDesires -> RelationOf Desires
case关于什么是 neighbors person r需要线来获取捕获的 Relation r Person Pet来自 RelationOf 的实例构造函数。存在性限定 GADT 捕获的实例只能通过对它们进行模式匹配来恢复。

等级 2 类型

使用 Rank 2 Type ,您需要添加以下内容之一
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE RankNTypes #-}

使用 Rank 2 Type,我们可以拆分 personPets分为两部分。第一个会弄清楚是什么 r是,要么 OwnsDesires ,并将其传递给 continuation passing style 中的通用量化函数.
withAttachment :: PetAttachment -> (forall r. Relation r Person Pet => r -> c) -> c
withAttachment AttachOwns f = f Owns
withAttachment AttachDesires f = f Desires
personPets将调用 withAttachment ,通过它一个部分应用 neighbours作为延续。
personPets :: Person -> PetAttachment -> Graph -> [Pet]
personPets person att = withAttachment att (neighbours person)

关于haskell - 存在类型歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25983955/

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