在准备考试时,我正在努力完成F#中的一些作业。
作业说:
考虑以下F#声明:
let rec f i = function | [] -> [i] | x::xs -> i+x :: f (i+1) xs
f
的类型为int -> int list -> int list
。表达式f 10 [0;1;2;3]
返回值[10;12;14;16;14]
。函数
f
不是尾递归。使用累积参数声明fA
的尾递归变体f
。和
声明
fC
的基于延续的尾递归变体f
。
到目前为止,我尝试过类似的事情:
let fA i =
let rec loop acc = function
| [] -> acc
| x::xs -> loop (i+x::acc) xs
loop i []
但我不明白为什么不与这些人合作。我知道我对这个有了更深刻的理解,所以现在我尝试了所有的大脑。
答案 0 :(得分:1)
嗯,你几乎就在那里 - 首先你可能还记得原来的f
有2个参数 - 所以你可能应该添加另一个:
let fA i xs = ...
然后原始更改i
- 因此你也应该(将它添加到循环中):
let fA i xs =
let rec loop i acc = function
然后你几乎就在那里 - 你只需要用正确的参数调用loop
,也许你有一个命令 -problem ...继续尝试:D
啊是的 - 正如@Sehnsucht所说 - 在某处您需要i+1
在那里...记得为什么你应该把i
带到你的loop
....
好的,您的acc
似乎有些问题 - 这里还有一行 - 您可以看到几乎没有任何变化:
let fA i xs =
let rec loop i acc = function
| ???
| x::xs -> loop (???) (???::acc) xs
???
显然你必须在???
个地方插入(不同的)东西:D
let fA i xs =
let rec loop i acc = function
| [] -> acc
| x::xs -> loop i (x::acc) xs
loop i [] xs
当然这不会正常工作,但会启动你的东西
你可能已经猜到了 - 从基于累加器到基于延续的方式并不是不同的(实际上这可能更容易 - 取决于你对向后 - 思考的使用方式) :
再次开始:
let fC i xs =
let rec loop i cont = function
如果遇到问题,也许你应该让编译器帮助你一点 - 为此添加cont
这样的类型:
let fC i xs =
let rec loop i (cont : int list -> int list) = function
现在请记住,随着时间的推移你必须创建新的延续 - 像(fun res -> ...something... |> cont)
那样作为新的延续传递。将res
视为使用列表的其余部分(您的xs
)执行我的操作的结果,那么它应该很容易。
对于第一次延续,你很可能根本不想做任何事......但这几乎总是一样的,所以你可能马上就知道了。
[] -> [i]
可能很讨厌... 是你现在错过了;) - 一旦你有了编译的东西(应该是你的第一个关注点)你会很快想出来我想i+x
和i+1
...不要忘记;)答案 1 :(得分:1)
我刚刚遇到这个问题,并认为这对我来说也很好。我分享了解决方案,希望能帮到某人。请把它当作一个简单的建议,而不是最好的解决方案。我只是一个没有计算机科学教育的F#仰慕者。
请注意我使用
let f list =
match list with
| ...
而不是原始的,更简洁的
let f =
function
| ...
因为前一种语法使f
的参数可见。
工作解决方案在这里:
// Original version
let rec f i list =
match list with
| [] -> [i]
| x::xs -> i+x :: f (i+1) xs
// Tail recursive version with accumulator
let fA i list =
let rec loop i acc list =
match list with
| x::xs ->
let newI = i + 1
let newAcc = x + i :: acc
let newList = xs
loop newI newAcc newList
| [] -> List.rev (i::acc)
loop i [] list
// Continuation based version
let fC i list =
let rec loop i (cont:int list -> int list) list =
match list with
| x::xs ->
let newI = i + 1
let newCont = fun res -> cont (x + i :: res)
let newList = xs
loop newI newCont newList
| [] -> cont (i::list)
loop i id list
// All these expressions evaluate to [10; 12; 14; 16; 14]
let res1 = f 10 [0..3]
let res2 = fA 10 [0..3]
let res3 = fC 10 [0..3]
如果可以改进其中一种解决方案,我将不胜感激。