Recursion F#递归地添加多项式
我试图用F#编写一个递归地添加多项式的函数。我的多项式可以表示为元组列表 例如,2x^4+3x^2+x+5等于[(2.0,4);(3.0,2);(1.0,1);(5.0,0)] 所有多项式都有适当的结构(没有相同次数的重复项,没有系数为零的项,除非它是零多项式,按递减指数排序的项没有空的输入列表) 我做这件事有困难。这是我的密码Recursion F#递归地添加多项式,recursion,f#,Recursion,F#,我试图用F#编写一个递归地添加多项式的函数。我的多项式可以表示为元组列表 例如,2x^4+3x^2+x+5等于[(2.0,4);(3.0,2);(1.0,1);(5.0,0)] 所有多项式都有适当的结构(没有相同次数的重复项,没有系数为零的项,除非它是零多项式,按递减指数排序的项没有空的输入列表) 我做这件事有困难。这是我的密码 type term = float * int type poly = term list let rec atp(t:term,p:poly):poly = m
type term = float * int
type poly = term list
let rec atp(t:term,p:poly):poly =
match p with
| [] -> []
| (a, b) :: tail -> if snd t = b then (fst t + a, b) :: [] elif snd t > b then t :: [] else ([]) :: atp(t, tail)
(* val atp : t:term * p:poly -> poly *)
let rec addpolys(p1:poly,p2:poly):poly =
match p1 with
| [] -> []
| (a,b) :: tail -> atp((a,b), p2) @ addpolys(tail, p2)
我有两个多项式
val p2 : poly = [(4.5, 7); (3.0, 4); (10.5, 3); (2.25, 2)]
val p1 : poly = [(3.0, 5); (2.0, 2); (7.0, 1); (1.5, 0)]
当我调用这个函数时,我的结果是
val p4 : poly =
[(4.5, 7); (3.0, 5); (3.0, 4); (3.0, 5); (10.5, 3); (3.0, 5); (4.25, 2)]
当正确答案是
[(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]
下面是一个完全通用的尾部递归实现:
let inline addPolys xs ys =
let rec imp acc = function
| (coeffx, degx)::xt, (coeffy, degy)::yt when degx = degy ->
imp ((coeffx + coeffy, degx)::acc) (xt, yt)
| (coeffx, degx)::xt, (coeffy, degy)::yt when degx > degy ->
imp ((coeffx, degx)::acc) (xt, (coeffy, degy)::yt)
| xs, yh::yt -> imp (yh::acc) (xs, yt)
| xh::xt, [] -> imp (xh::acc) (xt, [])
| [], yh::yt -> imp (yh::acc) ([], yt)
| [], [] -> acc
imp [] (xs, ys) |> List.rev
其类型为:
xs:( ^a * 'b) list -> ys:( ^a * 'b) list -> ( ^a * 'b) list
when ^a : (static member ( + ) : ^a * ^a -> ^a) and 'b : comparison
由于float
具有成员+
,并且int
支持比较,因此类型float*int
匹配这些通用约束:
> addPolys p1 p2;;
val it : (float * int) list =
[(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]
不幸的是,您的代码没有编译,因此我很难理解您的意图。但我有一个自己的解决方案。也许它会帮助你:
// addpoly: (float * 'a) list -> (float * 'a) list -> (float * 'a) list
let rec addpoly p1 p2 =
match (p1, p2) with
| [], p2 -> p2
| p1, [] -> p1
| (a1, n1)::p1s, (a2, n2)::p2s ->
if n1 < n2 then (a2, n2) :: addpoly p1 p2s
elif n1 > n2 then (a1, n1) :: addpoly p1s p2
else (a1+a2, n1) :: addpoly p1s p2s
let p1 = [(3.0, 5); (2.0, 2); ( 7.0, 1); (1.5, 0)]
let p2 = [(4.5, 7); (3.0, 4); (10.5, 3); (2.25, 2)]
let q = addpoly p1 p2
// val q : (float * int) list =
// [(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]
你也可以这样写
p1 = 1.5x^0 + 7.0x^1 + 2.0x^2 + 0.0x^3 + 0.0x^4 + 5.0x^5
因此,您可以使用以下列表定义多项式:
let p1 = [1.5; 7.0; 2.0; 0.0; 0.0; 5.0]
这里有两个对表示进行操作的函数。polyval计算给定值的结果,polyadd将两个多项式相加。实现方法非常简单:
// p1 = 1.5x^0 + 7.0x^1 + 2.0x^2 + 0.0x^3 + 0.0x^4 + 5.0x^5
let p1 = [1.5; 7.0; 2.0; 0.0; 0.0; 5.0]
// p2 = 0.0x^0 + 0.0x^1 + 2.25x^2 + 10.5x^3 + 3.0x^4 + 0.0x^5 + 0.0x^6 + 4.5x^7
let p2 = [0.0; 0.0; 2.25; 10.5; 3.0; 0.0; 0.0; 4.5]
// polyval: float list -> float -> float
let rec polyval ps x =
match ps with
| [] -> 0.0
| p::ps -> p + x * (polyval ps x)
// polyadd: float int -> float int -> float int
let rec polyadd ps qs =
match (ps, qs) with
| [], ys -> ys
| xs, [] -> xs
| x::xs, y::ys -> (x+y)::polyadd xs ys
let v = polyval p1 2.3
// val v : float = 349.99715
let p = polyadd p1 p2
// val p : float list = [1.5; 7.0; 4.25; 10.5; 3.0; 5.0; 0.0; 4.5]
您的代码在FSI中给了我一个错误:“错误FS0001:此表达式应具有类型term,但此处具有类型‘a list’。”请提供正确的代码。非常感谢,我只是想知道您花了多长时间来编写它。。因为我花了两个多小时写我的,但它甚至都不起作用!我想这只花了我不到15分钟的时间,但这只是因为我试图解决“使用F#函数编程”中的所有练习,所以我有很多练习。顺便说一句,这本书很棒。请注意这些实现不是尾部递归的。@mark seemann:是的,这是正确的。这些实现不是尾部递归的。但是在多项式的上下文中,这可能不是一个大问题,除非你想处理非常大的问题。
// p1 = 1.5x^0 + 7.0x^1 + 2.0x^2 + 0.0x^3 + 0.0x^4 + 5.0x^5
let p1 = [1.5; 7.0; 2.0; 0.0; 0.0; 5.0]
// p2 = 0.0x^0 + 0.0x^1 + 2.25x^2 + 10.5x^3 + 3.0x^4 + 0.0x^5 + 0.0x^6 + 4.5x^7
let p2 = [0.0; 0.0; 2.25; 10.5; 3.0; 0.0; 0.0; 4.5]
// polyval: float list -> float -> float
let rec polyval ps x =
match ps with
| [] -> 0.0
| p::ps -> p + x * (polyval ps x)
// polyadd: float int -> float int -> float int
let rec polyadd ps qs =
match (ps, qs) with
| [], ys -> ys
| xs, [] -> xs
| x::xs, y::ys -> (x+y)::polyadd xs ys
let v = polyval p1 2.3
// val v : float = 349.99715
let p = polyadd p1 p2
// val p : float list = [1.5; 7.0; 4.25; 10.5; 3.0; 5.0; 0.0; 4.5]