为什么F#没有列表元素的类型推断?

vik*_*ata 3 f# inference inline list

I was trying to put both int and float into a list construction:

> let l2=[1;2.0];;

  let l2=[1;2.0];;
  ----------^^^

stdin(50,11): error FS0001: This expression was expected to have type
    int
but here has type
    float
>
Run Code Online (Sandbox Code Playgroud)

好吧,如果我在Haskell中写l3 = [1,2.0],它可以构建列表以包含所有"小数"元素.为什么F#不支持自动类型推断?F#基于.net,Int和Float都是Object类型,对吧?为什么Int和Float无法放入一个列表中,而某些元素会自动进行类型提升或转换?似乎F#的类型系统使编写更多通用程序变得非常困难.

任何提示?

Mar*_*ann 11

F#没有类似Haskell的类型类.虽然它是基于.NET,在共同之间唯一的类型intfloatobjobj没有提供运营商,使您能够执行算术.

您仍然可以定义包含两者intfloat值的列表:

let l : obj list = [1; 2.0]
Run Code Online (Sandbox Code Playgroud)

但是,这几乎是无用的,因为除非您尝试向下转换它们,否则您无法这些值执行任何操作.它也不安全,因为这样的列表可以很容易地包含不是数字的值:

let l : obj list = [1; 2.0; "foo"]
Run Code Online (Sandbox Code Playgroud)

但是,所有这些都不会丢失,因为您可以使用inline关键字让编译器找出各种输入所需的运算符:

type Direction = Left = -1 | Straight = 0 | Right = 1

let inline turn (x1, y1) (x2, y2) (x3, y3) =
    let prod = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1)
    if prod > LanguagePrimitives.GenericZero then Direction.Left
    elif prod < LanguagePrimitives.GenericZero then Direction.Right
    else Direction.Straight
Run Code Online (Sandbox Code Playgroud)

此功能具有以下类型:

val inline turn :
  x1: ^a * y1: ^f -> x2: ^b * y2: ^g -> x3: ^j * y3: ^e -> Direction
    when ( ^b or  ^a) : (static member ( - ) :  ^b *  ^a ->  ^c) and
         ( ^j or  ^a) : (static member ( - ) :  ^j *  ^a ->  ^i) and
         ( ^c or  ^d) : (static member ( * ) :  ^c *  ^d ->  ^l) and
         ( ^e or  ^f) : (static member ( - ) :  ^e *  ^f ->  ^d) and
         ( ^g or  ^f) : (static member ( - ) :  ^g *  ^f ->  ^h) and
         ( ^h or  ^i) : (static member ( * ) :  ^h *  ^i ->  ^k) and
         ( ^l or  ^k) : (static member ( - ) :  ^l *  ^k ->  ^m) and
          ^m : (static member get_Zero : ->  ^m) and  ^m : comparison
Run Code Online (Sandbox Code Playgroud)

它声明a ^a^b是支持静态运算符-的类型^c,在使用时,它返回支持静态运算符的类型,*依此类推.

这个例子来自我的凸包示例.

它可以与both intfloatlists 一起使用,因为两种类型都支持所需的运算符:

> turn (1,2) (3,3) (2,1);;
val it : Direction = Right
> turn (1.0,2.0) (3.0,3.0) (2.0,1.0);;
val it : Direction = Right
Run Code Online (Sandbox Code Playgroud)

这并不像Haskell那么优雅,但它可以用在紧要关头.但在实践中,我不会错过很多.在我的职业生涯中,我很少会错过通用算法 ; 我发现它告诉我们一些商业上最成功的编程语言(Java,C#)不支持通用算法.