Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# f generic follow Expert Fsharp book示例出错_F# - Fatal编程技术网

F# f generic follow Expert Fsharp book示例出错

F# f generic follow Expert Fsharp book示例出错,f#,F#,我在读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.i

我在读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)
技巧3:必要时向泛型函数添加伪参数

技巧4:必要时添加显式类型参数,类似于tec 3

好的,在4种技术中的3种技术中,我需要先解析泛型代码,然后才能使用它…现在…返回书本示例…当编译器知道'key and'T'的值时

让dict=新字典>

在这个范围内,对于let 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() 
我承认我对静态类型语言有点无知这不是真正的泛型,因为在我使用它时它无法推断类型,我需要定义类型,然后传递值,而不是基于传递的值定义其类型,以其他方式定义类型,而不是显式的

非常感谢..非常感谢您对这一行的帮助

let dict = new Dictionary<'key,ResizeArray<'T>>();;
以后使用类型

let dict = new Dictionary<'key,ResizeArray<'T>>()
dict.[1] <- 2
使用函数

let dict() = new Dictionary<'key,ResizeArray<'T>>();;
对我来说,这段代码真的很难看,即使这是安全的,它看起来更像命令式语言,而不是函数式语言

我完全同意–这与您的直接问题有点相切,但我认为更惯用的功能性方法是:

let divideIntoEquivalenceClasses keyf seq =
    (System.Collections.Generic.Dictionary(), seq)
    ||> Seq.fold (fun dict v ->
        let key = keyf v
        match dict.TryGetValue key with
        | false, _ -> dict.Add (key, ResizeArray(Seq.singleton v))
        | _, prev  -> prev.Add v
        dict)
    |> Seq.map (function KeyValue (k, v) -> k, Seq.readonly v) 

这样就可以进行充分的类型推断,从一开始就不需要回答您的问题。

这实际上不会在一起定义时产生问题。也就是说,选择您发布的整个区块,并一次性将其发送给FSI。我明白了:

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.
val divideIntoEquivalenceClasses :
  ('T -> 'key) -> seq<'T> -> seq<'key * seq<'T>> when 'key : equality

但是,如果您将这些单独输入到FSI中,那么正如John Palmer所说,在这一孤立行中没有足够的信息供解释器确定类型约束。John的建议会起作用,但原始代码做得很正确-定义变量并在相同的范围内使用它,以便可以推断类型。

其他答案提出的解决方法都很好。根据你最近的更新,让我们考虑两个代码块:

let empties = Array.create 100 []
与之相反:

let empties = Array.create 100 []
empties.[0] <- [1]
每一行都将泛型类型参数“a”与不同的具体类型int和string统一起来。这两种统一都可以单独使用,但它们彼此不兼容,并且在执行第二行时会将第一行插入的int值1视为字符串,这显然违反了类型安全性

将此与空列表进行对比,空列表实际上是通用的:

let empty = []
然后,在本例中,编译器确实会推断为empty:“一个列表,因为将empty视为代码中不同位置的不同类型的列表是安全的,而不会影响类型安全性:

let l1 : int list = empty
let l2 : string list = empty
let l3 = 'a' :: empty
在make清空泛型函数的返回值的情况下:

let empties() = Array.create 100 []
同样,推断泛型类型是安全的,因为如果我们尝试之前的问题场景:

empties().[0] <- [1]
List.iter (printfn "%s") (empties().[0])
我们在每一行上创建一个新数组,因此类型可以不同,而不会破坏类型系统。
希望这有助于进一步解释限制背后的原因。

谢谢john,但我现在还不太清楚……当我在函数中编写dict时,编译器不知道什么是“键”和“不类型”……此函数处理数字、字母等。实际上,我需要一个:val dict:Dictionary>当“\u key:equality,请如果你能提供更多的细节或一些更详细的链接…谢谢@user1050817:函数可以是泛型的,值不能是泛型的。dict是用函数的泛型参数类型实例化的。@ildjarn-值不能是泛型的并不完全正确,例如try[],[],只是用于识别安全创建泛型值的一组启发式方法非常有限。@user1050817-关键是当您在函数中时,编译器有它没有的额外信息。当你打字时;;在fsi中,编译器必须进行函数调用,并且无法确定正确的通用字典-因此您会得到一个错误。than yamen,但我确实无法理解。为什么这是有效的:val divideIntoEquivalenceClasses:'t->'key->seq when'\u key:equality当我在函数中定义dict时,这没有足够的信息关于类型也没有…这必须与字母,数字等一起工作…但我不明白为什么有时工作,有时不…谢谢你的帮助!!。。。我认为您需要阅读@kvb的答案-在F中,两行程序和一行程序之间存在巨大差异。编译器需要在程序中进一步了解信息,以确保它知道正确的约束条件来推断类型。如果您试图一次键入并编译发送给FSI程序一行,它并不总是有足够的信息来正确推断。请注意,更新-在实际代码中很少出现值限制错误,推断通常可以从使用情况中获得信息
let divideIntoEquivalenceClasses keyf seq =
    (System.Collections.Generic.Dictionary(), seq)
    ||> Seq.fold (fun dict v ->
        let key = keyf v
        match dict.TryGetValue key with
        | false, _ -> dict.Add (key, ResizeArray(Seq.singleton v))
        | _, prev  -> prev.Add v
        dict)
    |> Seq.map (function KeyValue (k, v) -> k, Seq.readonly v) 
val divideIntoEquivalenceClasses :
  ('T -> 'key) -> seq<'T> -> seq<'key * seq<'T>> when 'key : equality
let empties = Array.create 100 []
let empties = Array.create 100 []
empties.[0] <- [1]
empties.[0] <- [1] // treat 'a list [] as int list []
List.iter (printfn "%s") empties.[0] // treat 'a list [] as string list []
let empty = []
let l1 : int list = empty
let l2 : string list = empty
let l3 = 'a' :: empty
let empties() = Array.create 100 []
empties().[0] <- [1]
List.iter (printfn "%s") (empties().[0])