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

时间:2015-01-29 05:12:30

标签: haskell typeclass type-systems

假设:

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只能使用Int64Unknown

但我们都知道

meh 1

会导致错误(文字“1”中没有(Num a0)的实例),因为1Num a => a而编译器不知道Num的哪个实例应该是。

但是,(逻辑上)可以将1推断为Int64因为它传递给mehmeh只能传递Int64 1}}或Unknown。换句话说,应该可以计算NumMeh的“交集”,并决定1是哪个实例。

所以我的问题是:你知道任何方式(编译器扩展,代码解决方法,任何东西)可以编写meh 1,其中1被正确推断为Int64没有添加类型签名或添加专门的功能?

1 个答案:

答案 0 :(得分:2)

在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:

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

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

然后即使在您的示例meh 1中也可以解析为(meh :: Int64 -> String) 1,通常它不能。{像“但基于范围中可见的Meh实例”这样的参数在Haskell中并不真正起作用,因为实例是全局的。


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

data Meh = MehInt Int64 | MehString String

instance IsString Meh where
   fromString = MehString

然后

"foo" :: Meh

将编译,因为GHC“将看到”

fromString "foo" :: Meh

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