我试图写一个函数来解决以下问题;
persistence 39 = 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
persistence 999 = 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
persistence 4 = 0 // because 4 is already a one-digit number在解决了这个问题之后,我试图使所有函数看起来像这样的Ramda.js函数样式;
let multiply = List.reduce (*)
let gt from input = input > from
let just input = fun _ -> input
let ifElse cond trueFn falseFn input =
if cond input then trueFn input else falseFn input
let digits n =
(string n) |> Seq.toList |> List.map (System.Char.GetNumericValue >> int)
let rec persRec iter current =
current
|> digits
|> multiply
|> ifElse (gt 9) (persRec (iter + 1)) (just iter)
let persistence n = if n > 9 then persRec 1 n else 0但是,当我试图修改persRec函数时,会出现如下所示的仓促合成版本,这会使堆栈溢出。
let rec persRec iter =
digits
>> multiply
>> ifElse (gt 9) (persRec (iter + 1)) (just iter)这是怎么回事?
发布于 2020-07-31 20:33:35
函数persRec无条件地调用自己。在此:
>> ifElse (gt 9) (persRec (iter + 1)) (just iter)
^^^^^^^^^^^^^^^^^^^^
|
unconditional recursive call这种事总是会发生。每次有人打电话给persRec,它都会立刻给自己打电话。
您可能期望递归调用只在gt 9时发生,因为毕竟,它在ifElse中,对吗?但这并不重要:ifElse并不特殊,它只是一个函数。为了调用一个函数,F#必须在调用之前计算它的所有参数(也称为“应用程序的计算顺序”),这意味着它必须在调用ifElse之前调用persRec (iter + 1),在调用(>>)之前必须调用ifElse,为了计算persRec的结果,它必须调用(>>)。因此,它最终需要调用persRec来计算persRec的结果。看看这是怎么回事?
上一个版本可以工作,因为persRec的主体在调用ifElse之前并没有实际执行。只有当提供了persRec的所有参数时,才会执行它的主体,而当条件为真时,才会在ifElse主体内提供最后一个参数。
在我看来,混乱的根源在于指称语义和操作语义之间的区别。是的,在数学上,逻辑上,这些函数是等价的。但死刑也很重要。正常的和应用的评估顺序。记忆问题。性能。这些都超出了λ-微积分的范畴。
https://stackoverflow.com/questions/63198414
复制相似问题