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



我刚开始学习F#,为了提高我的技能,我正在尝试2019年代码的出现。我正在尝试第 2 天的第一个谜题,但卡住了。请参阅底部第 2 天的规则。

我认为我遇到的问题是我不太明白编译器如何计算递归函数的返回类型。在这里看到我的尝试:

let rec intcode (arr: int []) op = // int [] -> int -> int []
let in1 = op + 1
let in2 = op + 2
let out = op + 3
match arr.[op] with
| 1 ->
arr.[arr.[out]] <- arr.[arr.[in1]] + arr.[arr.[in2]]
intcode arr op+4
| 2 ->
arr.[arr.[out]] <- arr.[arr.[in1]] * arr.[arr.[in2]]
intcode arr op+4
| 99 -> 
arr
| _ -> 
printfn "Had input operator that was not 1, 2, or 99"
arr

编译器给了我函数开头注释的函数签名,int [] -> int -> int [].

但是,编译器还告诉我,在尝试返回arr时匹配模式99时,error FS0001: The type 'int' does not match the type 'int []'

它是否告诉我它认为arrint?或者它认为函数的输出应该是一个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

解析为

(intcode arr 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

最新更新