递归模式匹配的F#返回类型

递归模式匹配的F#返回类型,f#,F#,我刚开始学习F#,为了提高我的技能,我正在努力学习。我正在尝试第二天的第一个谜题,结果被卡住了。请参见底部第2天的规则 我想我遇到的问题是,我不太明白编译器是如何计算递归函数的返回类型的。请参见我的尝试: let rec intcode(arr:int[])op=//int[]->int->int[] 设in1=op+1 设in2=op+2 放出=op+3 将arr[op]与 | 1 -> arr.[arr.[out]] arr.[arr.[out]] 啊 | _ -> printfn“具有不

我刚开始学习F#,为了提高我的技能,我正在努力学习。我正在尝试第二天的第一个谜题,结果被卡住了。请参见底部第2天的规则

我想我遇到的问题是,我不太明白编译器是如何计算递归函数的返回类型的。请参见我的尝试:

let rec intcode(arr:int[])op=//int[]->int->int[]
设in1=op+1
设in2=op+2
放出=op+3
将arr[op]与
| 1 ->
arr.[arr.[out]]
arr.[arr.[out]]
啊
| _ -> 
printfn“具有不是1、2或99的输入运算符”
啊
编译器给我在函数开头注释的函数签名,
int[]->int->int[]

但是,编译器还告诉我,在匹配模式
99
时尝试返回
arr
时,
错误FS0001:类型“int”与类型“int[]”不匹配。

它是不是告诉我它认为
arr
int
?或者它认为函数的输出应该是
int

规则

Intcode程序是由逗号分隔的整数列表(如1,0,0,3,99)。要运行一个,首先查看第一个整数(称为位置0)。在这里,您将找到一个操作码-1、2或99。操作码指示要执行的操作;例如,99表示程序已完成,应立即停止。遇到未知的操作码意味着出了问题

操作码1将从两个位置读取的数字相加,并将结果存储在第三个位置。紧跟在操作码之后的三个整数告诉您这三个位置-前两个表示您应该从中读取输入值的位置,第三个表示应该存储输出的位置

例如,如果您的Intcode计算机遇到1,10,20,30,它应该读取位置10和20处的值,将这些值相加,然后用它们的总和覆盖位置30处的值

操作码2的工作原理与操作码1完全相同,只是它将两个输入相乘,而不是相加。同样,操作码后面的三个整数指示输入和输出的位置,而不是它们的值

处理完一个操作码后,向前走4个位置,移动到下一个操作码

问题不是(直接)类型推断,而是类型推断

被解析为

(intcode arr op)+4
不是

因为函数应用程序的优先级高于
+
运算符

基于前面的分组,编译器推断表达式必须是
int
类型,因为最外层的表达式是
int
加法

要解决此问题,只需在
op+4

周围添加括号即可。问题不是(直接)类型推断,而是类型推断

被解析为

(intcode arr op)+4
不是

因为函数应用程序的优先级高于
+
运算符

基于前面的分组,编译器推断表达式必须是
int
类型,因为最外层的表达式是
int
加法


要解决此问题,只需在
op+4

周围添加括号。这不是问题的答案,而是原始问题的答案。 我想我应该把它改写成一个不变的版本。我希望它容易阅读

let run =
    let rec runr bp memory =
        let read  pos = memory |> Array.item (bp + pos)
        let read' pos = memory |> Array.item (read pos) 
        let write pos value = memory |> Array.mapi (fun i oldv -> if i = pos then value else oldv) 

        let exec op = op (read' 1) (read' 2) |> write (read 3)
        let apply op = runr (bp + 4) (exec op)

        match read 0 with
        | 1  -> apply (+)
        | 2  -> apply (*)
        | 99 -> memory
        | _  -> failwith "Invalid op code"

    runr 0

let result = run [|1;0;0;3;99|]
printf "%A" result

这不是对问题的回答,而是对原始问题的回答。 我想我应该把它改写成一个不变的版本。我希望它容易阅读

let run =
    let rec runr bp memory =
        let read  pos = memory |> Array.item (bp + pos)
        let read' pos = memory |> Array.item (read pos) 
        let write pos value = memory |> Array.mapi (fun i oldv -> if i = pos then value else oldv) 

        let exec op = op (read' 1) (read' 2) |> write (read 3)
        let apply op = runr (bp + 4) (exec op)

        match read 0 with
        | 1  -> apply (+)
        | 2  -> apply (*)
        | 99 -> memory
        | _  -> failwith "Invalid op code"

    runr 0

let result = run [|1;0;0;3;99|]
printf "%A" result