在Haskell v.Scara中输入推理

Kev*_*ith 4 haskell scala type-inference

给出以下代码:

Prelude> let f x = if (x) then 55 else "foo"
Run Code Online (Sandbox Code Playgroud)

为什么编译器会寻找Num [Char]

<interactive>:2:23:
    No instance for (Num [Char]) arising from the literal `55'
    In the expression: 55
    In the expression: if (x) then 55 else "foo"
    In an equation for `f': f x = if (x) then 55 else "foo"
Run Code Online (Sandbox Code Playgroud)

但是,在Scala中,它将找到55and 的最小上限"foo",即Any:

scala> def f(x: Boolean) = if (x) 55 else "foo"
f: (x: Boolean)Any

import scala.reflect.runtime.universe._

scala> lub( List[Type]( typeOf[Int], typeOf[String] ) )
res4: reflect.runtime.universe.Type = Any
Run Code Online (Sandbox Code Playgroud)

Haskell和Scala的类型推断之间的关键区别是什么?

bhe*_*ilr 8

您可以Num [Char]在Haskell中添加实例,如果这是您想要的:

{-# LANGUAGE FlexibleInstances #-}

import Data.Function (on)
import Data.Composition ((.:))  -- cabal install composition

helper :: (Integer -> Integer -> Integer) -> (String -> String -> String)
helper op = show .: on op read

cast :: (Integer -> Integer) -> (String -> String)
cast f = show . f . read

instance Num [Char] where
    fromInteger = show
    (+) = helper (+)
    (-) = helper (-)
    (*) = helper (*)
    abs = cast abs
    signum = cast signum
    negate = cast negate
Run Code Online (Sandbox Code Playgroud)

这只是一种可能的实现方式.这将使您的示例编译:

> let f x = if x then 55 else "foo"
> f True
"55"
> f False
"foo"
Run Code Online (Sandbox Code Playgroud)

Haskell具有多态数字文字,因此55 :: Num a => a,并且由于两个分支if必须返回相同的类型,因此强制a ~ [Char]使else分支返回"foo".这会导致一些有些混乱的错误消息,但它可能是一个非常强大的功能.这意味着,任何数字文本可以根据你的需要的类型为行动,它的背后同样的概念OverloadedStrings扩展,让你有多态性字符串文本而不是使用pack无处不在,你需要一个TextByteString.

Scala使用子类型,并且所有值都具有泛型类型.它允许您放松功能上的类型安全性并返回字面上的Any东西.Haskell根本没有子类型,因此统一这些类型(类似于查找LUB)的唯一方法是使用数值文字在Num约束下是多态的这一事实,因此为了编译"foo"必须实现Num.实际上,如果你启用了OverloadedStrings f将与该类型编译得很好

f :: (Data.String.IsString a, Num a) => Bool -> a
Run Code Online (Sandbox Code Playgroud)

默认情况下,没有任何类型满足这两个约束,但GHC很乐意接受它作为有效函数.