[英]Can the type of (a == b) be derived to be polymorphic?
由于(==) :: Eq a => a -> a -> Bool
,我希望
a == b :: Eq a => Bool
-- assuming a :: forall a. a
-- derived type
但是(根据GHCi :t
)
a == b :: Bool
当然,现在,这需要TypeApplications
,因此默认情况下不应启用它,但是是否有LANGUAGE
选项可启用此功能?
NoMonomorphismRestriction
不起作用。
编辑:既然您可能会说,“嗯,GHC(i)在任何实际示例中都已经知道a
和b
的类型”,例如,不,您可以拥有(5 == 5) :: (Num a, Eq a) => Bool
。
编辑:似乎a :: forall a. a
a :: forall a. a
是不可能的,所以让我们假设类似x = 5 :: Num a => a
编辑:明确声明该类型有效 ,所以问题实际上是“ GHC可以推断此类型为多态吗”,所以我正在寻找类似DeriveAmbiguousTypes
东西。
这就是(==)
的类型:
(==) :: forall a. Eq a => a -> a -> Bool
(==)
接受四个参数, 顺序为 :
a
,种Type
(AKA *
) Eq a
类型的字典, a
的值。 a
的值。 与往常一样,部分应用程序只能按顺序工作 ,并且字典参数不能显式传递。 此外,类型参数只能在使用前引入。 因此,当您编写a == b
,这实际上意味着
(==) @_ @{dict} a b
推断出类型实参和字典实参,您将获得类型Bool
的值。
您追求的是与(==)
不同的类型:
numLitEq
:: (forall a. (Num a, Eq a) => a)
-> (forall b. (Num b, Eq b) => b)
-> forall c. (Num c, Eq c) => Bool
numLitEq a b = (==) @c a b
但是,您不能完全这样写,因为无法将c
类型变量放入作用域。 你能做的最好的就是
numLitEq
:: forall c.
(forall a. (Num a, Eq a) => a)
-> (forall b. (Num b, Eq b) => b)
-> (Num c, Eq c) => Bool
numLitEq a b = (==) @c a b
这比仅使用(==)
更好。
实际上,这至少在GHC-8.2和8.3中有效。
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Prelude> :set -XRank2Types -XUnicodeSyntax
Prelude> let x, y :: ∀ a . a; (x,y) = (undefined,undefined)
Prelude> :set -XAllowAmbiguousTypes
Prelude> let p :: ∀ a . Eq a => Bool; p = x==y
Prelude> :set -XTypeApplications
Prelude> p @Int
*** Exception: Prelude.undefined
CallStack (from HasCallStack):
error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
undefined, called at <interactive>:3:36 in interactive:Ghci1
Prelude> p @(String -> Double)
<interactive>:11:1: error:
• No instance for (Eq (String -> Double)) arising from a use of ‘p’
(maybe you haven't applied a function to enough arguments?)
• In the expression: p @(String -> Double)
In an equation for ‘it’: it = p @(String -> Double)
请注意,如果您只是问是否可以将表达式3 == 5
设为3
和5
的类型,那么答案是肯定的。 必须借助某些语言扩展来明确给出签名,但是以下定义是多态的:
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module ThreeFive where
eq35 :: forall a . (Num a, Eq a) => Bool
eq35 = (3 :: a) == 5
另外,您可以使用TypeApplications
:
eq35' :: forall a . (Num a, Eq a) => Bool
eq35' = (==) @a 3 5
现在,GHCi将eq35
的类型报告为Bool
,但这是一个谎言,您可以通过添加+v
标志来看到:
> :type eq35
eq35 :: Bool
> :type +v eq35
eq35 :: (Num a, Eq a) => Bool
或通过证明:
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- Holistic number are all equal
newtype Holistic = Holistic Int deriving (Num)
instance Eq Holistic where
_ == _ = True
main = do print (eq35 @Int)
print (eq35 @Holistic)
运行此命令将输出False
和True
。
我看不到任何语言扩展的组合,在没有显式类型签名的情况下,GHC可以自动推断出3 == 5
比True
更通用的类型。 同样,尽管x
和y
可能是多态的,否则x == y
将默认为单态类型或被拒绝,除非您使用上述显式签名。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.