gpt4 book ai didi

haskell - 类型推断和函数依赖的混淆

转载 作者:行者123 更新时间:2023-12-02 15:14:03 25 4
gpt4 key购买 nike

我有以下多参数类型类,其功能依赖于作为向量空间(向量)元素的类型

module Vec where

class Vec v k | v -> k where -- v is an element of a vector space over k
vZero :: v -- The zero vector in v
vAdd :: v -> v -> v -- Adds two vectors
vSub :: v -> v -> v -- Subtracts two vectors
vMul :: v -> k -> v -- Multiplies a vector by a number from k

infixl 6 |+| -- Shortcut operator for accessing vAdd
(|+|) :: Vec v k => v -> v -> v
(|+|) = vAdd

现在,我将上面的代码加载到 ghci 解释器中,并要求它显示运算符 |+| 的类型:

*Vec> :t (|+|)
(|+|) :: Vec v k => v -> v -> v

到目前为止,一切似乎都很正常。但现在我想指定所有数字都是其自身之上的特殊向量空间的元素:

instance Num k => Vec k k where
vZero = 0
vAdd = (+)
vSub = (-)
vMul = (*)

现在发生了一件奇怪的事情:ghci 不再显示 |+| 的正确类型(尽管我在上面的代码中明确指定了它):

*Vec> :t (|+|)
(|+|) :: Num v => v -> v -> v

我怀疑这种奇怪的行为与我正在使用的 FunctionalDependencies 语言扩展有关,但我不明白为什么 ghc 会这样。我可以看到自己添加了一个不同的实例 Vec v k,其中 v不是 Num 的实例,因此这样的实例不会与现有的重叠,从而保留功能依赖性。

最佳答案

您已经定义了非常通用的实例:Vec v ...。如果没有重叠的实例,就不可能有其他实例。

例如添加

data V2 k = V2 k k
instance Num k => Vec (V2 k) k where

结果

Functional dependencies conflict between instance declarations:
instance Num k => Vec k k -- Defined at v.hs:15:10
instance Num k => Vec (V2 k) k -- Defined at v.hs:23:10

实际上重叠实例在这里也没有帮助(这可能是 GHC 的缺失功能?)。

如果您尝试使用 TypeFamilies 对其进行编码,您会收到类似的错误:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Vec where

class Vec v where -- v is an element of a vector space over k
type Elem v
vZero :: v -- The zero vector in v
vAdd :: v -> v -> v -- Adds two vectors
vSub :: v -> v -> v -- Subtracts two vectors
vMul :: v -> Elem v -> v -- Multiplies a vector by a number from k

infixl 6 |+| -- Shortcut operator for accessing vAdd
(|+|) :: Vec v k => v -> v -> v
(|+|) = vAdd

data V2 k = V2 k k

instance Num k => Vec (V2 k) where
type Elem (V2 k) = k
-- implementation omitted

instance Num k => Vec k where
type Elem k = k
vZero = 0
vAdd = (+)
vSub = (-)
vMul = (*)

错误:

Conflicting family instance declarations:
Elem (V2 k) -- Defined at v.hs:20:10
Elem k -- Defined at v.hs:23:10
<小时/>

解决方案是定义辅助函数并“手动”编写实例定义:

{-# LANGUAGE FlexibleInstances, FunctionalDependencies #-}
module Vec where

class Vec v k | v -> k where -- v is an element of a vector space over k
vZero :: v -- The zero vector in v
vAdd :: v -> v -> v -- Adds two vectors
vSub :: v -> v -> v -- Subtracts two vectors
vMul :: v -> k -> v -- Multiplies a vector by a number from k

infixl 6 |+| -- Shortcut operator for accessing vAdd
(|+|) :: Vec v k => v -> v -> v
(|+|) = vAdd

-- The definitions are so short, that it's not worth even givin them names
numVZero :: Num k => k
numVZero = 0

instance Vec Int Int where
vZero = 0
vAdd = (+)
vSub = (-)
vMul = (*)

data V2 k = V2 k k
instance Num k => Vec (V2 k) k where
vZero = V2 0 0
vAdd (V2 a b) (V2 c d) = V2 (a + c) (b + d)
vSub (V2 a b) (V2 c d) = V2 (a - c) (b - d)
vMul (V2 a b) k = V2 (a * k) (b * k)

然后:

λ *Vec > :t (|+|)
(|+|) :: Vec v k => v -> v -> v
<小时/>

或者,由于 Num v => Vec v v 可能会很常见,您可以使用 DefaultSignatures减少实例声明的样板:

{-# LANGUAGE GADTs, FlexibleInstances, FunctionalDependencies, DefaultSignatures #-}
module Vec where

class Vec v k | v -> k where -- v is an element of a vector space over k
vZero :: v -- The zero vector in v
default vZero :: (Num v, v ~ k) => v
vZero = 0

vAdd :: v -> v -> v -- Adds two vectors
default vAdd :: (Num v, v ~ k) => v -> v -> v
vAdd = (+)

vSub :: v -> v -> v -- Subtracts two vectors
default vSub :: (Num v, v ~ k) => v -> v -> v
vSub = (-)

vMul :: v -> k -> v -- Multiplies a vector by a number from k
default vMul :: (Num v, v ~ k) => v -> k -> v
vMul = (*)

infixl 6 |+| -- Shortcut operator for accessing vAdd
(|+|) :: Vec v k => v -> v -> v
(|+|) = vAdd

instance Vec Int Int
instance Vec Integer Integer
instance Vec Float Float
instance Vec Double Double

data V2 k = V2 k k
instance Num k => Vec (V2 k) k where
vZero = V2 0 0
vAdd (V2 a b) (V2 c d) = V2 (a + c) (b + d)
vSub (V2 a b) (V2 c d) = V2 (a - c) (b - d)
vMul (V2 a b) k = V2 (a * k) (b * k)

关于haskell - 类型推断和函数依赖的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34471950/

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