【发布时间】:2012-04-18 00:06:27
【问题描述】:
我正在阅读 Expert F# 书籍,我发现了这段代码
open System.Collections.Generic
let divideIntoEquivalenceClasses keyf seq =
// The dictionary to hold the equivalence classes
let dict = new Dictionary<'key,ResizeArray<'T>>()
// Build the groupings
seq |> Seq.iter (fun v ->
let key = keyf v
let ok,prev = dict.TryGetValue(key)
if ok then prev.Add(v)
else let prev = new ResizeArray<'T>()
dict.[key] <- prev
prev.Add(v))
dict |> Seq.map (fun group -> group.Key, Seq.readonly group.Value)
示例使用:
> divideIntoEquivalenceClasses (fun n -> n % 3) [ 0 .. 10 ];;
val it : seq<int * seq<int>>
= seq [(0, seq [0; 3; 6; 9]); (1, seq [1; 4; 7; 10]); (2, seq [2; 5; 8])]
首先对我来说这段代码真的很难看,即使这是安全的,它看起来更像命令式语言而不是函数式语言..特别是与 clojure 相比。但问题不在于这个......我的字典定义有问题
当我输入这个时:
let dict = new Dictionary<'key,ResizeArray<'T>>();;
我明白了:
pruebafs2a.fs(32,5): error FS0030: Value restriction. The value 'dict' has been inferred to have generic type
val dict : Dictionary<'_key,ResizeArray<'_T>> when '_key : equality
Either define 'dict' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
可以吗?...
非常感谢
改进问题:
好的,我一直在阅读有关价值限制的信息,发现这些信息很有帮助
特别是,只有函数定义和简单的不可变数据 表达式自动泛化
...好吧..这就解释了原因
let dict = new Dictionary<'key,ResizeArray<'T>>();;
不起作用...并展示了 4 种不同的技术,尽管在我看来它们只能解决错误,但不是使用通用代码的解决方案:
技巧 1:将值限制为非泛型
let empties : int list [] = Array.create 100 []
技巧 3:必要时为泛型函数添加伪参数
let empties () = Array.create 100 []
let intEmpties : int list [] = empties()
技巧 4:必要时添加显式类型参数(类似于 tec 3)
let emptyLists = Seq.init 100 (fun _ -> [])
> emptyLists<int>;;
val it : seq<int list> = seq [[]; []; []; []; ...]
----- 也是唯一一个让我使用真正的通用代码------ 技巧 2:确保泛型函数具有显式参数
let mapFirst = List.map fst //doesn't work
let mapFirst inp = List.map fst inp
好的,在 4 种技术中的 3 种技术中,我需要先解决通用代码,然后才能使用它...现在...返回书本示例...当编译器知道 'key 和 'T 的值时
让 dict = new Dictionary>()
在范围内,代码非常通用,让 key 可以是任何类型,'T
也是如此最大的问题是:
当我将代码包含在函数中时(技巧 3):
let empties = Array.create 100 [] //doesn't work
let empties () = Array.create 100 []
val empties : unit -> 'a list []
I need define the type before begin use it
let intEmpties : int list [] = empties()
对我来说(诚然我对静态类型语言有点笨)这不是真正的通用,因为当我使用它时它无法推断类型,我需要定义类型然后传递值(而不是定义它的类型基于传递的值)存在其他方式定义类型而不是如此明确..
非常感谢..非常感谢任何帮助
【问题讨论】:
-
更新注意事项——在实际代码中很少会遇到值限制错误,推断通常可以从使用中提取出来
标签: f#