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
>
好吧,如果我在Haskell中写l3 = [1,2.0],它可以构建列表以包含所有“小数”元素。为什么F#不支持自动类型推断? F#基于.net,Int和Float都是Object类型,对吧?为什么Int和Float无法放入一个列表中,而某些元素会自动进行类型提升或转换?似乎F#的类型系统使编写更多通用程序变得非常困难。
任何提示?
答案 0 :(得分:11)
F#没有类似Haskell的类型类。虽然它基于.NET,但int
和float
之间唯一的共同类型是obj
,而obj
没有提供使您能够执行算术的运算符。
仍然,您可以定义包含int
和float
值的列表:
let l : obj list = [1; 2.0]
这接近无用,因为除非您尝试向下转换它们,否则不能执行具有这些值的任何内容。它也是不安全,因为这样的列表很容易包含不是数字的值:
let l : obj list = [1; 2.0; "foo"]
然而,所有这些都不会丢失,因为您可以使用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
此功能具有以下类型:
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
它指出^a
和^b
是支持静态运算符-
的类型,在使用时返回类型^c
,它支持静态运算符{ {1}},等等。
此示例取自my convex hull example。
它可以与*
和int
列表一起使用,因为这两种类型都支持所需的运算符:
float
这并不像Haskell那么优雅,但它可以在紧要关头使用。但在实践中,我不会错过很多。在我的职业生涯中,我很少想念泛型算术;我发现它说一些商业上最成功的编程语言(Java,C#)不支持通用算法。