简体   繁体   English

简单递归上的F#隐式键入阻塞

[英]F# implicit typing choking on simple recursion

When I define a recursive function in F# thus: 当我在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

...all is good. ...一切都很好。 When I attempt to avoid the "empty list" problem thus: 因此,当我尝试避免出现“空列表”问题时:

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

...I get yelled at: ...我大吼:

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

What am I missing here? 我在这里想念什么?

From the docs : 文档

The types of the values produced in each branch must match. 每个分支中产生的值的类型必须匹配。 If there is no explicit else branch, its type is unit . 如果没有显式else分支,则其类型为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. 因此,如果then分支的类型是除unit以外的任何类型,则必须存在一个具有相同返回类型的else分支。

You're missing said 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

(Nb I've used elif here rather than nesting another if expression; hopefully that's not too much of a distraction.) (注:我在这里使用的是elif ,而不是嵌套另一个if表达式;希望这不会引起太多干扰。)

That said, your logic involving startState is highly suspect; 就是说,您极有可能涉及startState的逻辑; it's always zero, and really serves no purpose here. 它始终为零,在这里实际上没有任何作用。 Your state should probably be a parameter rather than a local value so it can be used as an accumulator: 您的状态可能应该是参数而不是局部值,因此它可以用作累加器:

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

Lastly, let's make it idiomatic: 最后,让我们习惯用法:

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

which can be shortened to 可以缩短为

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

With ildjarns answer, I think I would suggest that one could/should go all the way... 有了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

(And I never remember left or right here, so... ;-) (而且我永远都不记得在这里的左或右,所以... ;-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM