Haskell中是否可以实现严格类型和相等性检查?

3

想知道以下代码在Haskell中是否可行?

equal :: a -> b -> Bool
equal a b = a == b
2个回答

10

不,(==) 的类型要求其参数具有相同的类型

(==) :: Eq a => a -> a -> Bool

你问是否有可能(测试不同类型之间的相等性),是的,这是可能的,但通常不会这样做。您可以使用Typeable来证明ab是相同的类型,但您需要对它们都施加Typeable约束(以及任何一个的Eq约束)

{-# Language ScopedTypeVariables #-}
{-# Language TypeApplications    #-}
{-# Language ConstraintKinds     #-}
{-# Language GADTs               #-}

import Type.Reflection

type Equal a b = (Eq a, Typeable a, Typeable b)

equal :: forall a b. Equal a b => a -> b -> Bool
equal x y =
  case eqTypeRep (typeRep @a) (typeRep @b) of
    -- In this branch, `a' and `b' are the SAME type
    -- so `(==)' works
    Just HRefl -> x == y

    -- Values of different types are never equal
    Nothing -> False

所以下面的代码是有效的

>> equal 10 'a'
False
>> equal 'X' 'a'
False
>> equal 'X' 'X'
True

请确保您理解为什么我们只约束其中一个 Eq a/Eq b,而这个选择并不重要。


我尝试运行那段代码,但出现了类型变量a和b不在作用域内的错误,请参见此处的详细信息-> https://pastebin.com/izWi4f9J - Don Klein
1
@DonKlein:使用ScopedTypeVariables定义ab的作用域时,缺少forall量词。(现在对我有效。) - Jon Purdy
出于好奇,这里的 @ 表示什么意思? - Don Klein
@DonKlein f x 将值 x 应用于函数 f,而 f @ a 将类型(而非值)a 应用于 f。后者假设 f :: forall t. .... 并选择 ta。例如,id @ (Int, Bool) (3, True) 首先将 identity 函数推广到一个 pair 类型,然后将其应用于一个 pair;在这里没有实际需要指定 @(Int,Bool),因为类型推断器可以从 (3,True) 推断出它。相反,上面的 typeRep 没有值参数来推动推断,并且必须提供类型。 - chi
typeRep @atypeRep :: TypeRep a 是相同的,也可以写成:eqTypeRep (typeRep :: TypeRep a) (typeRep :: TypeRep b)。它需要在 ghci 中启用 :set -XTypeApplications,非常有用。 - Iceland_jack
感谢所有的技巧,从来没有想过通过提问可以学到这么多诀窍 :) - Don Klein

3
尽管由于“==”的签名,Eq不允许您定义该函数,但是您可以定义自己的类型类来解决这个问题:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

class Eqq a b where
  eqq :: a -> b -> Bool

-- Just an example of a possible instance for general types
instance Eqq a b where
  eqq a b = True 

并且,接下来,
equal :: (Eqq a b) => a -> b -> Bool
equal a b = a `eqq` b

1
@Iceland_jack 这个代码并不按预期运行,但是你可以使用 Typeable 给类型类 Eqq 装备你的答案(顺便说一下,这真是个好答案),它可以比较类型,并在两个类型相同时使用 == - nicodp
啊,我明白了。 - Iceland_jack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接