假设:
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
会导致错误(文字“1”中没有(Num a0)的实例),因为1
是Num a => a
而编译器不知道Num
的哪个实例应该是。
但是,(逻辑上)可以将1
推断为Int64
因为它传递给meh
而meh
只能传递Int64
1}}或Unknown
。换句话说,应该可以计算Num
和Meh
的“交集”,并决定1
是哪个实例。
所以我的问题是:你知道任何方式(编译器扩展,代码解决方法,任何东西)可以编写meh 1
,其中1
被正确推断为Int64
没有添加类型签名或添加专门的功能?
答案 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时这种情况很方便。