F# 隐式键入在简单递归上窒息

F# implicit typing choking on simple recursion

当我在 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

...一切都很好。当我试图这样避免 "empty list" 问题时:

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

我在这里错过了什么?

来自 the docs:

The types of the values produced in each branch must match. If there is no explicit else branch, its type is unit. Therefore, if the type of the then branch is any type other than unit, there must be an else branch with the same return type.

你没说 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

有了 ildjarns 的回答,我想我会建议 could/should 一路走下去...

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

(而且我从不记得左或右,所以... ;-)