想知道以下代码在Haskell中是否可行?
equal :: a -> b -> Bool
equal a b = a == b
不,(==)
的类型要求其参数具有相同的类型
(==) :: Eq a => a -> a -> Bool
你问是否有可能(测试不同类型之间的相等性),是的,这是可能的,但通常不会这样做。您可以使用Typeable
来证明a
和b
是相同的类型,但您需要对它们都施加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
,而这个选择并不重要。
{-# 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
Typeable
给类型类 Eqq
装备你的答案(顺便说一下,这真是个好答案),它可以比较类型,并在两个类型相同时使用 ==
。 - nicodp
ScopedTypeVariables
定义a
和b
的作用域时,缺少forall
量词。(现在对我有效。) - Jon Purdy@
表示什么意思? - Don Kleinf x
将值x
应用于函数f
,而f @ a
将类型(而非值)a
应用于f
。后者假设f :: forall t. ....
并选择t
为a
。例如,id @ (Int, Bool) (3, True)
首先将 identity 函数推广到一个 pair 类型,然后将其应用于一个 pair;在这里没有实际需要指定@(Int,Bool)
,因为类型推断器可以从(3,True)
推断出它。相反,上面的typeRep
没有值参数来推动推断,并且必须提供类型。 - chitypeRep @a
和typeRep :: TypeRep a
是相同的,也可以写成:eqTypeRep (typeRep :: TypeRep a) (typeRep :: TypeRep b)
。它需要在 ghci 中启用:set -XTypeApplications
,非常有用。 - Iceland_jack