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

时间:2019-06-11 11:21:22

标签: haskell types polymorphism

(==) :: 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的类型”,例如,您可以拥有{{1 }}。
编辑:似乎(5 == 5) :: (Num a, Eq a) => Bool是不可能的,所以让我们假设类似a :: forall a. a

编辑:明确声明类型行之有效,所以问题实际上是“ GHC可以推断这种类型为多态吗”,所以我正在寻找类似x = 5 :: Num a => a的东西。

>

3 个答案:

答案 0 :(得分:4)

这与(==)的类型有关:

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

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

  1. 类型为a(又称Type)的类型*
  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

这并不比仅使用(==)更好。

答案 1 :(得分:1)

实际上,这至少在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)

答案 2 :(得分:1)

请注意,如果您只是问是否可以将3 == 53类型的表达式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)

并运行此命令将打印FalseTrue

我没有看到任何形式的语言扩展组合,它们可以使GHC自动{em> 为3 == 5推断比True更通用的类型,而无需明确类型签名。同样,尽管多态xy可能是这样,x == y要么默认为单态类型,要么被拒绝,除非您使用上述显式签名。