F#隐式类型在简单递归时窒息

时间:2017-01-23 19:55:47

标签: recursion syntax f# implicit-typing

当我在F#中定义递归函数时:

let rec recursiveSum inputs =
    let startState = 0.0m

    if List.length inputs = 1 then
        startState + inputs.Head
    else
        let t = List.tail inputs
        startState + inputs.Head + recursiveSum t

......一切都很好。当我试图避开"空列表"问题因此:

let rec recursiveSum inputs =
    let startState = 0.0m

    **if List.isEmpty inputs then startState**

    if List.length inputs = 1 then
        startState + inputs.Head
    else
        let t = List.tail inputs
        startState + inputs.Head + recursiveSum t

......我被大吼:

recursion.fsx(5,9): error FS0001: This expression was expected to have type
    unit    
but here has type
    decimal

我在这里缺少什么?

2 个答案:

答案 0 :(得分:3)

来自the docs

  

每个分支中生成的值的类型必须匹配。如果没有明确的else分支,则其类型为unit。因此,如果then分支的类型是除unit以外的任何类型,则必须有一个具有相同返回类型的else分支。

你错过了说else

let rec recursiveSum inputs =
    let startState = 0.0m

    if List.isEmpty inputs then 0.0m
    elif List.length inputs = 1 then
        startState + inputs.Head
    else
        let t = List.tail inputs
        startState + inputs.Head + recursiveSum t

(N.b。我在这里使用elif而不是嵌套另一个if表达式;希望这不会太分散注意力。)

那就是说,涉及startState的逻辑非常可疑;它始终为零,在这里真的没有用处。您的状态应该是参数而不是本地值,因此它可以用作累加器:

let recursiveSum inputs =
    let rec impl state inputs =
        if List.isEmpty inputs then state
        elif List.length inputs = 1 then
            state + inputs.Head
        else
            let t = List.tail inputs
            impl (state + inputs.Head) t
    impl 0.0m inputs

最后,让我们把它变成惯用语:

let recursiveSum inputs =
    let rec impl state inputs =
        match inputs with
          | []   -> state
          | [h]  -> state + h
          | h::t -> impl (state + h) t
    impl 0.0m inputs

可以缩短为

let recursiveSum inputs =
    let rec impl state = function
      | []   -> state
      | h::t -> impl (state + h) t
    impl 0.0m inputs

答案 1 :(得分:2)

随着ildjarns的回答,我想我会建议一个人可以/应该一路走下去......

let rec fold f acc = function 
        | [] -> acc
        | [x] -> f x acc
        | h::t -> fold f (f h acc) t




let someDec = [0.1m; 0.2m]
let someStr = ["world"; "Hello "]

someDec
|> fold (+) 0.0m

someStr
|> fold (+) ""


let recursiveSum = fold (+) 0.0m    

someDec
|> recursiveSum


let recursiveStrAdd = fold (+) ""

someStr
|> recursiveStrAdd


someDec
|> recursiveSum

(我永远不会记得左边或右边,所以...; - )