Haskell “存在量化”与情商实例

Haskell “存在量化”与情商实例,haskell,Haskell,当我尝试使用存在主义量化时,我遇到了一个问题 让我们假设你有一个类型 data T s = forall s. (Show s,Eq s) => T (String,s) 我想为这种类型编写一个实例Eq,比如: instance Eq (T a) where (T (name,value)) == (T (name',value')) | (name /= name') = False |

当我尝试使用存在主义量化时,我遇到了一个问题

让我们假设你有一个类型

data T s = forall s. (Show s,Eq s) => T (String,s)
我想为这种类型编写一个实例Eq,比如:

instance Eq (T a) where
    (T (name,value)) == (T (name',value'))  | (name /= name') = False
                                            | otherwise = value == value'
但它失败了:

Could not deduce (s1 ~ s)
from the context (Show s, Eq s)
另一个实例声明

instance Eq a => Eq (T a) where
结果相同错误:

   Could not deduce (s1 ~ s)
    from the context (Eq a)

每次打开存在数据类型时,都会暴露一段类型已被遗忘的数据。为了处理这个问题,Haskell必须为这个数据从无到有地建立一个类型,因此它会生成一个完全唯一的、新鲜的类型变量

这意味着,如果你打开两个不同的存在主义,那么无论你做什么,新的类型都不会一致。这就是您收到的错误消息的含义

当然,这也是正确的行为。例如,我们需要使用T构造函数的全部内容是Show和Eq的实例。Int和String都满足这一点,因此以下两个值都是有效值

data T = forall s. (Show s,Eq s) => T (String,s)

x, y :: T
x = T ("string", "string")
y = T ("int", 3)
但是我们不能期望String或Int的Eq实例足以像实例Eq T尝试做的那样比较3==String

那么如何解决这个问题呢?我们需要一个平等的概念,无论存储在T中的数据是什么类型,它都是有效的

data T = forall s . T String s (s -> (String, Int))
其中,T的第三个参数是一个函数,它生成表示中所示的值和一个我们将用于相等的整数散列值

instance Eq T where
  T nm1 s1 f1 = T nm2 s2 f2 = 
    nm1 == nm2 && snd (f1 s1) == snd (f2 s2)
现在这是可行的,但是如果我们能用匿名类型的值做的唯一一件事就是将它应用到它的copatriot匿名类型函数中,那么表示会引起一个问题。。。那为什么不一开始就这么做呢

data T = T String String Int

t :: Show s => String -> s -> (s -> Int) -> T
t nm s f = T nm (show s) (f s)

每次打开存在数据类型时,都会暴露一段类型已被遗忘的数据。为了处理这个问题,Haskell必须为这个数据从无到有地建立一个类型,因此它会生成一个完全唯一的、新鲜的类型变量

这意味着,如果你打开两个不同的存在主义,那么无论你做什么,新的类型都不会一致。这就是您收到的错误消息的含义

当然,这也是正确的行为。例如,我们需要使用T构造函数的全部内容是Show和Eq的实例。Int和String都满足这一点,因此以下两个值都是有效值

data T = forall s. (Show s,Eq s) => T (String,s)

x, y :: T
x = T ("string", "string")
y = T ("int", 3)
但是我们不能期望String或Int的Eq实例足以像实例Eq T尝试做的那样比较3==String

那么如何解决这个问题呢?我们需要一个平等的概念,无论存储在T中的数据是什么类型,它都是有效的

data T = forall s . T String s (s -> (String, Int))
其中,T的第三个参数是一个函数,它生成表示中所示的值和一个我们将用于相等的整数散列值

instance Eq T where
  T nm1 s1 f1 = T nm2 s2 f2 = 
    nm1 == nm2 && snd (f1 s1) == snd (f2 s2)
现在这是可行的,但是如果我们能用匿名类型的值做的唯一一件事就是将它应用到它的copatriot匿名类型函数中,那么表示会引起一个问题。。。那为什么不一开始就这么做呢

data T = T String String Int

t :: Show s => String -> s -> (s -> Int) -> T
t nm s f = T nm (show s) (f s)

为了进一步阐述我的观点,下面是你可以做的

{-# LANGUAGE ExistentialQuantification #-}
module E where
import Data.Typeable

data T = forall s. (Show s, Eq s, Typeable s) => T String s

instance Eq T where
    T name value == T name' value' = name == name' && maybe False (== value') (cast value)

这假设如果存在式中的类型不同,那么值之间的比较就不应该相等。

要展开我的评论,请看下面的方法

{-# LANGUAGE ExistentialQuantification #-}
module E where
import Data.Typeable

data T = forall s. (Show s, Eq s, Typeable s) => T String s

instance Eq T where
    T name value == T name' value' = name == name' && maybe False (== value') (cast value)

这假设如果存在式中的类型不同,那么值之间的比较就不应该相等。

首先,为什么要写数据ts,不是说数据ts吗?s完全是幻影,因为它与构造函数中使用的s不同。第二,你不能推导Eq,因为不能保证value和value的类型相同,那么你如何比较它们呢?您可以通过向约束中添加Typeable并使用cast进行类型转换来实现,但您必须自己编写Eq实例。是的,数据T这是我的错误,我将尝试使用TypeCasting您确定需要这一切吗?也许数据ts=Show s,Eq s=>T String,s就是您要找的?@user3237465我必须在我的项目中使用异构列表。@SergeySosnin您确定必须使用异构列表吗?如果您已经确定这是最好的方法,我不会争辩,但我经常看到在使用异构列表的情况下,它们只会使事情变得更复杂。首先,为什么要编写数据ts,您不是说数据ts吗?s完全是幻影,因为它与构造函数中使用的s不同。第二,你不能推导Eq,因为不能保证value和value的类型相同,那么你如何比较它们呢?您可以通过向约束中添加Typeable并使用cast进行类型转换来实现,但您必须自己编写Eq实例。是的,数据T这是我的错误,我将尝试使用TypeCasting您确定需要这一切吗?也许数据ts=Show s,Eq s=>T String,s就是您要找的?@user3237465我必须在我的项目中使用异构列表。@SergeySosnin您确定必须使用异构列表吗?如果你已经确定这是最好的方法,我不会争辩, 但我经常看到,在使用异构列表时,它们只会使事情变得更加复杂。