F#,试图理解表达式的范围 - 这应该有用吗?

时间:2016-05-24 04:45:53

标签: scope f#

这是财务算法的高度骨架化版本。在实际条件和数据处理中有更多的逻辑由" myFunc" - 在这个版本中真正意图有意义。

我的问题是:我如何理解为什么在这个区块中使用firstMultiple是允许的和合理的。它为什么要起作用?

表达式直接从标记为A的行映射到标记为C3的行,其中使用了其值。但随后在C1C2 - (大致)相同级别的"缩进"作为C3 - 这里分配了firstMultiple - 看起来好像它是可变的 - ??

我想我不明白为什么C3使用firstMultipleC1似乎会覆盖它。 (调试器,并运行它,表明它没关系)。

我希望这个问题和示例可以让我们深入了解如何思考(嵌套)范围。 (我很高兴当然也对设计有其他意见,但请记住,这段代码非常缺乏大量的分析。)(而且我可能在我剥离它时使算法不合逻辑,但我试图关注范围问题。)

let rec ListBuilder factor firstMultiple useFirstMultiple inputList outputList = // "A"    
    match inputList with
    | [] -> []
    | h::[] -> List.rev (inputList.Head :: outputList) 
    | _ ->
        let nextInput = inputList.Head
        let newOutputList, remInputList, firstMultiple =    // "B"
            match outputList with
            | [] ->  //first pass, capture firstMultiple now
                let firstMultiple = nextInput * factor      // "C1" 
                [nextInput], inputList.Tail, firstMultiple  // "C2"
            | _ ->                                             
                let lastOutput = outputList.Head
                let multiple = 
                    if useFirstMultiple then firstMultiple  // "C3"
                                        else lastOutput * factor
                let newOutputList =
                    if (myfunc multiple nextInput: bool) then  
                        nextInput :: outputList
                    else
                        outputList
                let remInputList =
                    if not (myfunc multiple nextInput: bool) then     
                        inputList.Tail
                    else
                        inputList
                newOutputList, remInputList, firstMultiple 
        ListBuilder factor firstMultiple useFirstMultiple remInputList newOutputList 

2 个答案:

答案 0 :(得分:3)

由于此示例基本上是

的循环
let rec ListBuilder 
    ...
    ListBuilder

C3中每个项目的循环点击outputlist,然后当outputlist为空时,最终点击C1C2

仅在C3 firstMultiple读取。

then firstMultiple  // "C3"

C1C2firstMultiplebound然后阅读,请注意我说bound不是setmutated

let firstMultiple = nextInput * factor      // "C1" 
[nextInput], inputList.Tail, firstMultiple  // "C2"

C1 firstMultiplefirstMultipleAB的{​​{1}}变量不同,它是一个新变量。因此,当您认为它在C3位置firstMultiple变异时,它不是。

如果您的示例转换正确,那么您可以将代码转换为:

C3

或更简单

let temp = nextInput * factor      // "C1"
[nextInput], inputList.Tail, temp  // "C2"

在此示例中[nextInput], inputList.Tail, (nextInput * factor) // "C2" firstMultipleC1只是一个重用的变量名称,因为允许使用阴影,但不需要。

修改

OP在评论中提出了进一步的问题:

  

为什么行" B"从" C2"中取出第一个多个而不是来自" A"。

原因是行C2是三个值的元组,它们是由行B后面的表达式的结果生成的。所有这些都是为元组创建三个值的表达式。

B

根据匹配结果生成三个元组值的两行是

    let newOutputList, remInputList, firstMultiple =    // "B"
        match outputList with
        | [] ->  //first pass, capture firstMultiple now
            let firstMultiple = nextInput * factor      // "C1" 
            [nextInput], inputList.Tail, firstMultiple  // "C2"
        | _ ->                                             
            let lastOutput = outputList.Head
            let multiple = 
                if useFirstMultiple then firstMultiple  // "C3"
                                    else lastOutput * factor
            let newOutputList =
                if (myfunc multiple nextInput: bool) then  
                    nextInput :: outputList
                else
                    outputList
            let remInputList =
                if not (myfunc multiple nextInput: bool) then     
                    inputList.Tail
                else
                    inputList
            newOutputList, remInputList, firstMultiple 

[nextInput], inputList.Tail, firstMultiple  // "C2"

newOutputList, remInputList, firstMultiple 不是以B作为参数的函数,例如

firstMultiple

它是一个匹配函数,返回三个值的元组

let myFunc firstMultiple = ...

let newOutputList, remInputList, firstMultiple = // "B" 未通过firstMultiple传递 但是被创建为一个新变量并绑定在B

C1

然后通过let firstMultiple = nextInput * factor // "C1"

返回
C2

答案 1 :(得分:2)

内部范围可以捕获外部范围中的变量。我假设您的问题意味着您在分配新值时期望出现错误。阴影和实际可变变量之间存在差异。见这两个例子。

这里x不是实际可变的,虽然它感觉像是:

let testValue (l: int list) =
    let x = l.[0]
    printfn "%A" x
    do
        let x= l.[1]
        printfn "%A" x
    printfn "%A" x
    let x = l.[2]
    printfn "%A" x 

这里x实际上是可变的:

let testValue2 (l: int list) =
    let mutable x = l.[0]
    printfn "%A" x
    x <- l.[1]
    printfn "%A" x

使用testValue [1;2;3]

尝试