繁体   English   中英

(a == b)的类型能否派生为多态的?

[英]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)在任何实际示例中都已经知道ab的类型”,例如,不,您可以拥有(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

(==)接受四个参数, 顺序为

  1. A型, a ,种Type (AKA *
  2. Eq a类型的字典,
  3. 类型为a的值。
  4. 类型为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设为35的类型,那么答案是肯定的。 必须借助某些语言扩展来明确给出签名,但是以下定义是多态的:

{-# 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)

运行此命令将输出FalseTrue

我看不到任何语言扩展的组合,在没有显式类型签名的情况下,GHC可以自动推断出3 == 5True更通用的类型。 同样,尽管xy可能是多态的,否则x == y将默认为单态类型或被拒绝,除非您使用上述显式签名。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM