我有这么简单的"投资"输入"生命周期"属性:
type Investment = {
PurchasePayment: float;
Lifetime: float;
TaxWriteoff: float;
ResidualValue: float;
}
let CoffeMachine = {
PurchasePayment = 13000.0;
Lifetime = 4.0;
TaxWriteoff = 2000.0;
ResidualValue = 500.0;
}
我想重复多年的投资并每年进行一些计算:
for i = 1 to int CoffeMachine.Lifetime do
printf "%i" i
// doSomething
有没有办法避免使用for循环并以更实用的方式编写?
干杯,
Wojtek
答案 0 :(得分:5)
对列表中的每个项目执行计算的首选方法称为cd /opt/PetaLinux
sudo chmod 777 PetaLinux$petalinux-v2017.1-finalinstaller.run
./Petalinux-v2017.1-finalinstaller.run
。具体而言,对于您的情况,您可以创建一个从1到map
的数字列表,然后使用Lifetime
对每个数字执行计算:
List.map
那就是说,我认为你把“功能性”与“难以理解”(或者,也许是“炫耀”)混为一谈。 “函数式编程”的要点不是所有的数学,也不是无法接受的。 “函数式编程”的意思是“用函数编程”。这有一些实际意义,例如“不可变数据”和“无副作用”,只要您的程序满足这些要求,您就可以将其视为“功能性”,无论它看起来多么简单。事实上,我认为它看起来越简单越好。软件可维护性是一个非常有价值的目标。
特别是,如果你只想打印多年,那么你的代码就可以了:打印出来本身是一种“副作用”,所以只要这是一个要求,就没有办法让它更具“功能性” ”。但是如果你的目标是进行一些计算(如上面的例子中那样),那么可以用列表理解来表达清晰度:
let calculation year = year * 2 // substitute your calculation here
let calcResults = [1..int CoffeMachine.Lifetime] |> List.map calculation
答案 1 :(得分:2)
我很快找到答案:
[1..int CoffeMachine.Lifetime] |> List.iter (printf "%i")
答案 2 :(得分:1)
与其他答案不同的方法是使用尾递归。
例如尾递归有什么好处?
[1..int CoffeMachine.Lifetime] |> List.iter (printf "%i")
或者:
for i = 1 to int CoffeMachine.Lifetime do
printf "%i" i
从性能和内存的角度来看,List.iter
比for loop
更糟糕,因为第一个创建一个链表(F#不可变列表是引擎盖下的单链表)并迭代它。在许多情况下,增加的CPU和内存使用量并不相关,但在其他情况下则是如此。
像Seq
这样的惰性集合会缓解这种情况,但不幸的是Seq
目前在F#中效率不高。 Nessos Streams将是更好的选择。
F#中for loop
的问题在于它不能过早地中断(F#中不存在break
或continue
。)
此外,for loop
模式通常会在聚合结果时强制我们进入可变变量模式。
尾递归允许我们在不依赖可变变量的情况下聚合结果并支持中止。另外,尾递归循环可以返回for loop
不能的值(表达式结果总是unit
)
尾部递归在F#中也很有效,因为F#检测尾递归函数并将其展开到引擎盖下的循环中。
这是上面代码的尾递归循环的样子:
let rec loop i l = if i <= l then printf "%i" i; loop (i + 1) l
loop 1 (int CoffeMachine.Lifetime)
使用ILSpy
看到这被编译成一个while循环:
internal static void loop@3(int i, int l)
{
while (i <= l)
{
PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit> format = new PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit, int>("%i");
PrintfModule.PrintFormatToTextWriter<FSharpFunc<int, Unit>>(Console.Out, format).Invoke(i);
int arg_28_0 = i + 1;
l = l;
i = arg_28_0;
}
}
答案 3 :(得分:0)
一些递归方法的简短示例。通常,您只需使用.iter或.map。
let rec map f = function
| [] -> []
| h::t -> f h::map f t
map (fun x->x+1) [1;2;3]
let rec iter f = function
| [] -> ()
| h::t ->
f h
iter f t
签名:
for iter, f:('a -> unit)
for map, f:('a -> 'b)
您也可以获得标准的循环语法:
for i in [0 .. 4] do
printfn "%i" i
for i = 0 to 4 do
printfn "%i" i
要以函数方式使用for循环,这种语法很方便:
[for i in [0..10]->i]
[for i = 0 to 10 do yield i]
请注意
List.map f [0..10]相当于[for i in [0..10] - &gt; i]