为了学习更多F#,我尝试实现Paul Graham here所描述的“累加器生成器”。到目前为止,我最好的解决方案是完全动态键入:
open System
let acc (init:obj) : obj->obj=
let state = ref init
fun (x:obj) ->
if (!state).GetType() = typeof<Int32>
&& x.GetType() = typeof<Int32> then
state := (Convert.ToInt32(!state) + Convert.ToInt32(x)) :> obj
else
state := (Convert.ToDouble(!state) + Convert.ToDouble(x)) :> obj
!state
do
let x : obj -> obj = acc 1 // the type annotation is necessary here
(x 5) |> ignore
printfn "%A" (x 2) // prints "8"
printfn "%A" (x 2.3) // prints "10.3"
我有三个问题:
x
的类型注释,则代码将无法编译,因为编译器会推断出x的int -> obj
类型,尽管acc
带有注释以返回obj->obj
。为什么会这样,我可以避免吗? 最佳答案
为了学习更多F#,我尝试实现Paul Graham在此描述的“累加器生成器”。
此问题需要存在未指定的数字塔。 Lisp恰好有一个,并且恰好适合Paul Graham的例子,因为这个问题是专门为使Lisp看起来人为地设计的。
您可以使用联合类型(例如type number = Int of int | Float of float
)或通过将所有内容装箱在F#中实现数字塔。以下解决方案使用后一种方法:
let add (x: obj) (y: obj) =
match x, y with
| (:? int as m), (:? int as n) -> box(m+n)
| (:? int as n), (:? float as x)
| (:? float as x), (:? int as n) -> box(x + float n)
| (:? float as x), (:? float as y) -> box(x + y)
| _ -> failwith "Run-time type error"
let acc x =
let x = ref x
fun (y: obj) ->
x := add !x y
!x
let x : obj -> _ = acc(box 1)
do x(box 5)
do acc(box 3)
do printfn "%A" (x(box 2.3))
但是,数字塔在现实世界中几乎没有用。除非您非常谨慎,否则尝试从这些沉闷的挑战中学习将使您弊大于利。您应该问自己,为什么我们不想要数字塔,不想装箱并且不想运行时类型提升?
我们为什么不只写:
let x = 1
let x = x + 5
ignore(3)
let x = float x + 2.3
我们知道每一步
x
的类型。每个数字都未装箱存储。我们知道这段代码永远不会产生运行时类型错误...关于f# - F#中的累加器生成器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3644107/