从上下文中猜测 Num 的正确实例

Guessing the correct instance of Num from the context

假设:

import Data.Int (Int64)

data Unknown

class Meh a where
    meh :: a -> String
instance Meh Int64 where
    meh = show
instance Meh Unknown where
    meh _ = "Unknown"

很明显,meh只能取一个Int64或一个Unknown

但我们都知道

meh 1

会导致错误(No instance for (Num a0) arising from the literal '1')因为 1Num a => a 并且编译器不知道 [=17= 的哪个实例] 应该是。

但是,(逻辑上)应该可以推断出 1 是一个 Int64,因为它被传递给 mehmeh 只能接受一个Int64Unknown。换句话说,应该可以计算NumMeh的"intersection"并决定1是哪个实例。

所以我的问题是:您是否知道有什么方法(编译器扩展、代码解决方法等)可以编写 meh 1,其中 1 被正确推断为 Int64 不添加类型签名或添加专用函数?

在 GHC 7.8.3 中尝试您的示例时

>>> meh 1

我得到:

<interactive>:2:1:
    No instance for (Meh a0) arising from a use of ‘meh’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Meh Unknown -- Defined at Meh.hs:9:10
      instance Meh Int64 -- Defined at Meh.hs:7:10
    In the expression: meh 1
    In an equation for ‘it’: it = meh 1

<interactive>:2:5:
    No instance for (Num a0) arising from the literal ‘1’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
    ...

这是因为编译器试图进行类型检查:

>>> meh (fromInteger (1 :: Integer))

你得到类似的错误:

<interactive>:4:1:
    No instance for (Meh a0) arising from a use of ‘meh’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Meh Unknown -- Defined at Meh.hs:9:10
      instance Meh Int64 -- Defined at Meh.hs:7:10
    In the expression: meh (fromInteger (1 :: Integer))
    In an equation for ‘it’: it = meh (fromInteger (1 :: Integer))

<interactive>:4:6:
    No instance for (Num a0) arising from a use of ‘fromInteger’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:

Type-类 已打开。没有人限制别人定义:

newtype MyInt = MyInt Int deriving (Num)
instance Meh MyInt where
   meh = ...

那么即使在你的例子中meh 1也可以解析为(meh :: Int64 -> String) 1,一般情况下是不行的。 "but based on the Meh instances visible in the scope" 之类的参数在 Haskell 中实际上不起作用,因为实例是全局的。


如果您定义 data(已关闭),则使用 {-# LANGUAGE OverloadedStrings #-} 您可以:

data Meh = MehInt Int64 | MehString String

instance IsString Meh where
   fromString = MehString

然后

"foo" :: Meh

将编译为 GHC "will see"

fromString "foo" :: Meh

同样,您可以定义不完整的 Num 实例,仅定义 fromInteger。然而,我个人不喜欢不完整的实例,尽管这种情况在定义 eDSL 时很方便。