这就是我到目前为止所拥有的。感觉很接近,但我不确定如何解决第 84 行中的问题(第二行到最后一行: elif List.append(isolate(a),isolate(b)) != [] then List.append(isolate(a),隔离(b)))。
(* val isolate : l:'a list -> 'a list when 'a : equality *)
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then
let xs = remove (x,l)
isolate xs
else isolate xs
( * val common : 'a list * 'a list -> 'a list when 'a : equality *)
let rec common (k: 'a list, l:'a list) =
match ((k:'a list),(l:'a list)) with
| (a, b) ->
if a=[] then []
elif b=[] then []
elif List.append(isolate(a),isolate(b)) != [] then List.append(isolate(a),isolate(b))
else []
编辑:
要求发布完整代码:
(* val sumlist : l:float list -> float *)
let rec sumlist l =
match (l:float list) with
| [] -> 0.0
| a::x -> (sumlist x) + a
(* :: creates a list. *)
sumlist([1.0;2.0;3.0])
(* val squarelist : l:float list -> float list *)
let rec squarelist l =
match (l:float list) with
| [] -> []
| a::x -> (a*a)::(squarelist x)
(* val mean : l:float list -> float *)
let mean l =
match (l:float list) with
| [] -> 0.0
| l -> (sumlist l)/(float)l.Length
mean([1.0;2.0;3.0])
(* val mean_diffs : l:float list -> float list *)
let mean_diffs l =
match l with
set a = mean(l)
| [] -> []
let rec diffs (a,l)=
match l with
| x::xs -> (x-(mean(l))::diffs(xs)
| [] -> l
mean_diffs([1.0;2.0;3.0])
(* val variance : l:float list -> float *)
let variance l =
match (l:float list) with
| [] -> 0.0
| l -> (sumlist (squarelist (mean_diffs l)))/(float)l.Length
(* End of question 1 *) (* Do not edit this line. *)
(* Question 2 *) (* Do not edit this line. *)
(* val memberof : 'a * 'a list -> bool when 'a : equality *)
let rec memberof l=
match (l: 'a * 'a list) with
| (t,[]) -> false
| (t, x::xs) when t=x -> true
| (t, x::xs) -> t=x || memberof(t,xs)
(* val remove : 'a * 'a list -> 'a list when 'a : equality *)
let rec remove ((k:'a),(l:'a list)) =
match l with
| [] -> []
| x::xs when x=k -> xs
| x::xs ->x::(remove(k,xs))
(* End of question 2 *) (* Do not edit this line *)
(* Question 3 *) (* Do not edit this line *)
(* val isolate : l:'a list -> 'a list when 'a : equality *)
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then
let xs = remove (x,l)
isolate xs
else isolate xs
(* End of question 3 *) (* Do not edit this line *)
(* Question 4 *) (* Do not edit this line *)
(* val common : 'a list * 'a list -> 'a list when 'a : equality *)
let rec common (k: 'a list, l:'a list) =
match ((k:'a list),(l:'a list)) with
| (a, b) ->
if a=[] then []
elif b=[] then []
elif List.append(isolate(a),isolate(b)) <> [] then List.append(isolate(a),isolate(b))
else []
common([1.0;2.0;6.0;10.0],[5.0;6.0;10.0])
看来<>已经解决了这个问题,但是你对我的函数mean_diffs有什么建议吗?
最佳答案
由于这看起来您正在学习一门类(class),并且它是建立在之前的练习基础上的,因此代码将转换为更符合 F# 习惯的递归函数和标准化格式,以便在您访问 currying 时更容易使用它们。请参阅:F# for fun and profit和 Functions as First-Class Values (F#)以及其他更先进的概念。
格式基本上是
let funXYZ list =
let rec funXYZInner list acc =
match list with
| head :: tail ->
let acc = (somefunc head) :: acc
funXYZInner tail acc
| [] -> acc
funXYZInner list []
其中 funXYZ 是一个没有 rec 的公开函数名称。我不记得来源了,但是如果你可以实现一个需要rec并且rec不被暴露的函数,那么它会使代码更加可移植。
基本概念是获取一个列表并将该列表分为head
和tail
:
head :: tail
然后你处理头部:
somefunc head
然后将结果累加到累加器
let acc = value :: acc
let acc = value + acc
let acc = acc + (value * value)
然后处理列表的其余部分,例如tail,传递累加器
funXYZInner tail acc
当输入列表匹配空时
| []
只返回累加器中累加的结果
acc
内部函数 funXYZInner 确实有一个 rec并使用 accumulator ,即acc
。这将有助于理解如何使用 tail calls这将防止您在大型计算中耗尽内存。
您可能已经知道,使用 match
语句您希望覆盖 match 变量的所有情况。这是因为algebraic data types这就是您看到有关并非所有案例都被涵盖的警告的原因。如果您看到这些警告之一并且不知道为什么会收到它,则需要修复它们,否则就会面临意外运行时错误或崩溃的风险。
虽然您提供的代码只能用于浮点类型列表,但将来要使其适用于更多类型,您将需要了解 LanguagePrimitives.GenericZero<^T> Type Function (F#) .
由于需要而添加了一些更基本的功能,例如反向
,并帮助显示随着示例变得更加复杂的进展。
事实上,示例是建立在自身之上的,并且您在上一个示例中出现了特定错误,因此最好为示例提供更好的基础,这应该可以减轻首次学习递归函数时遇到的常见问题。
关于累加器,累加器可以保存不同的类型,例如float
、list
、int
,并且递归函数中可以使用多个累加器,例如分子Acc
,分母Acc
。另外,通过提取累加器值的计算,例如 let acc = ...
,当您使用更高级的函数时,您可以传入一个函数来替换该计算。
有一个predicate不使用累加器的函数memberof
。谓词是一个返回 true 或 false 的函数,一旦达到所需的值,您就可以停止处理列表的其余部分。
还值得注意的是,虽然某些函数可以调用早期定义的函数,但示例不会进行调用,以便它们可以一次性处理列表。当函数使用列表调用其他函数时,每个函数都必须处理整个列表才能返回结果。通过使用rec函数,有时可以通过对头部进行多次计算来处理一次列表。然而,有时这是无法做到的。我没有以某种方式最大化功能,而是给它们留下了一种为学习提供更多变化的方式。请随意重写它们,这将导致 function composition .
您可能会对这些示例有更多疑问,因此请作为单独的问题提出,而不是在此问题的基础上提出。
所有代码
// val reverse : l:'a list -> 'a list
let reverse l =
let rec reverseInner l acc =
match l with
| x::xs ->
let acc = x :: acc
reverseInner xs acc
| [] -> acc
reverseInner l []
reverse [ 3.0; 2.0; 1.0 ] // val it : float list = [1.0; 2.0; 3.0]
// val length : l:'a list -> int
let length l =
let rec lengthInner l acc =
match l with
| x::xs ->
let acc = acc + 1
lengthInner xs acc
| [] -> acc
lengthInner l 0
length [ 3.0; 2.0; 1.0 ] // val it : int = 3
// val sum : l:float list -> float
let sum l =
let rec sumInner l acc =
match l with
| x::xs ->
let acc = acc + x
sumInner xs acc
| [] -> acc
sumInner l 0.0
sum [ 1.0; 2.0; 3.0 ] // val it : float = 6.0
// val square : l:float list -> float list
let square (l : float list) =
let rec squareInner l acc =
match l with
| x::xs ->
let acc = (x * x) :: acc
squareInner xs acc
| [] -> reverse acc
squareInner l []
square [ 1.0; 2.0; 3.0 ] // val it : float list = [1.0; 4.0; 9.0]
// val mean : l:float list -> float
let mean l =
let rec meanInner l sumacc lengthacc =
match l with
| x::xs ->
let sumacc = sumacc + x
let lengthacc = lengthacc + 1.0
meanInner xs sumacc lengthacc
| [] -> sumacc / lengthacc
meanInner l 0.0 0.0
mean([1.0;2.0;3.0]) // val it : float = 2.0
// val mean_diffs : l:float list -> float list
let meanDiff l =
let rec meanDiffInner l m acc =
match l with
| x::xs ->
let diff = (x - m)
let acc = diff :: acc
meanDiffInner xs m acc
| [] -> reverse acc
meanDiffInner l (mean l) []
meanDiff [ 1.0; 2.0; 3.0 ] // val it : float list = [-1.0; 0.0; 1.0]
// From: https://en.wikipedia.org/wiki/Variance
// Suppose a population of numbers consists of 3, 4, 7, and 10.
// The arithmetic mean of these numbers, often informally called the "average", is (3+4+7+10)÷4 = 6.
// The variance of these four numbers is the average squared deviation from this average.
// These deviations are (3–6) = –3, (4–6) = –2, (7–6) = 1, and (10–6) = 4.
// Thus the variance of the four numbers is ((-3)^2 + (-2)^2 + (1)^2 + (4)^2) / 4 = 15/2 = 7.5
// val variance : l:float list -> float
let variance l =
let deviations = meanDiff l
let rec varianceInner l numeratorAcc denomenatorAcc =
match l with
| devation::xs ->
let numeratorAcc = numeratorAcc + (devation * devation)
let denomenatorAcc = denomenatorAcc + 1.0
varianceInner xs numeratorAcc denomenatorAcc
| [] -> numeratorAcc / denomenatorAcc
varianceInner deviations 0.0 0.0
variance [ 1.0; 2.0; 3.0 ] // val it : float = 0.6666666667
variance [ 3.0; 4.0; 7.0; 10.0 ] // val it : float = 7.5
(* End of question 1 *) (* Do not edit this line. *)
(* Question 2 *) (* Do not edit this line. *)
// val memberof : l:'a list -> item:'a -> bool when 'a : equality
let memberof l item =
let rec memberInner l item =
match l with
| x::xs ->
if x = item then
true
else
memberInner xs item
| [] -> false
memberInner l item
memberof [ 1.0; 2.0; 3.0 ] 0.0 // val it : bool = false
memberof [ 1.0; 2.0; 3.0 ] 1.0 // val it : bool = true
memberof [ 1.0; 2.0; 3.0 ] 2.0 // trueval it : bool = true
memberof [ 1.0; 2.0; 3.0 ] 3.0 // val it : bool = true
memberof [ 1.0; 2.0; 3.0 ] 4.0 // val it : bool = false
// val remove : l:'a list -> item:'a -> 'a list when 'a : equality
let remove l item =
let rec removeInner l item acc =
match l with
| x::xs ->
if x = item then
removeInner xs item acc
else
let acc = x :: acc
removeInner xs item acc
| [] -> reverse acc
removeInner l item []
remove [ 1.0; 2.0; 3.0 ] 0.0 // val it : float list = [1.0; 2.0; 3.0]
remove [ 1.0; 2.0; 3.0 ] 1.0 // val it : float list = [2.0; 3.0]
remove [ 1.0; 2.0; 3.0 ] 2.0 // val it : float list = [1.0; 3.0]
remove [ 1.0; 2.0; 3.0 ] 3.0 // val it : float list = [1.0; 2.0]
remove [ 1.0; 2.0; 3.0 ] 4.0 // val it : float list = [1.0; 2.0; 3.0]
(* End of question 2 *) (* Do not edit this line *)
(* Question 3 *) (* Do not edit this line *)
// val isolate : list:'a list -> 'a list when 'a : equality
let isolate list =
let rec isolateInner searchList commonlist =
match searchList with
| x::xs ->
if (memberof commonlist x) then
isolateInner xs commonlist
else
let commonlist = (x :: commonlist)
isolateInner xs commonlist
| [] -> reverse commonlist
isolateInner list []
isolate [ 1.0; 2.0; 3.0 ] // val it : float list = [1.0; 2.0; 3.0]
isolate [ 1.0; 1.0; 2.0; 3.0 ] // val it : float list = [1.0; 2.0; 3.0]
isolate [ 1.0; 2.0; 2.0; 3.0 ] // val it : float list = [1.0; 2.0; 3.0]
isolate [ 1.0; 2.0; 3.0; 3.0 ] // val it : float list = [1.0; 2.0; 3.0]
isolate [ 3.0; 2.0; 1.0; 1.0; 2.0; 3.0; 2.0; 1.0; 1.0; 3.0] // val it : float list = [3.0; 2.0; 1.0]
(* End of question 3 *) (* Do not edit this line *)
(* Question 4 *) (* Do not edit this line *)
// val common : a:'a list -> b:'a list -> 'a list when 'a : equality
let common a b =
let rec commonInner a b acc =
match (a,b) with
| (x::xs,b) ->
if (memberof acc x) then
commonInner xs b acc
else
let acc = x :: acc
commonInner xs b acc
| ([],y::ys) ->
if (memberof acc y) then
commonInner [] ys acc
else
let acc = y :: acc
commonInner [] ys acc
| ([],[]) -> reverse acc
commonInner a b []
common [ 1.0; 2.0; 6.0; 10.0] [ 5.0; 6.0; 10.0 ] // val it : float list = [1.0; 2.0; 6.0; 10.0; 5.0]
关于list - F#:递归函数:连接 2 个具有公共(public)元素的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35098970/