gpt4 book ai didi

Fatal error: exception Invalid_argument("String.sub / Bytes.sub")(致命错误:异常INVALID_ARGUMENT(“String.Sub/Bytes.Sub”))

转载 作者:bug小助手 更新时间:2023-10-28 13:25:09 26 4
gpt4 key购买 nike



I am learning OCaml and working my way through the advent of code 2022.

我正在学习OCaml,并在代码2022的到来中努力工作。


But it seems that reading the input.txt file is causing some issue.

但似乎读取input.txt文件会导致一些问题。


A X
B Y
C Z

I am getting this strange error, that comes from the func score. Particularly the expression call scorer hd. Though, when I manually set the lines variable to a list string, everything works.

我收到了这个奇怪的错误,它来自于函数分数。尤其是那个叫得分手HD的表达。不过,当我手动将LINS变量设置为列表字符串时,一切都正常。


The error occurs here inside the func scorer:

在函数记分器中出现以下错误:


    | hd :: tail -> score_helper tail scorer (scorer hd + acc)

let read_lines filename =
let contents = In_channel.with_open_bin filename In_channel.input_all in
String.split_on_char '\n' contents

let lines = read_lines "input.txt"

let score input scorer =
let rec score_helper input scorer acc =
match input with
| [] -> acc
| hd :: tail -> score_helper tail scorer (scorer hd + acc)
in
score_helper input scorer 0

(* Gets called on every row, returns the score value *)
let scorer s =
let theirs =
match String.sub s 0 1 with
| "A" -> "X"
| "B" -> "Y"
| "C" -> "Z"
| _ -> assert false
in
let ours = String.sub s 2 1 in
let played =
match ours with "X" -> 1 | "Y" -> 2 | "Z" -> 3 | _ -> assert false
in
let result =
match (theirs, ours) with
| "X", "Y" | "Y", "Z" | "Z", "X" -> 6
| theirs, ours when theirs = ours -> 3
| _ -> 0
in
played + result

let () = Format.sprintf "Part 1: %d" (score lines scorer) |> print_endline


更多回答
优秀答案推荐

The problem is revealed by inspecting lines:

这个问题是通过检查线路发现的:


# lines;;
- : string list = ["A X"; "B Y"; "C Z"; ""]
#

Note the last element: ""! You most likely want to ignore this empty line.

请注意最后一个元素:“”!您很可能希望忽略这一空行。


A simple way to handle this case is to ignore this blank lines in the score function:

处理这种情况的一种简单方法是忽略Score函数中的空行:


let score input scorer =
let rec score_helper input scorer acc =
match input with
| [] -> acc
| "" :: tail -> score_helper tail scorer acc
| hd :: tail -> score_helper tail scorer (scorer hd + acc)
in
score_helper input scorer 0


jthuhlu has identified the source of your problem.

Jthorhlu已经确定了您问题的根源。


However, there is another way to approach your problem. Your score function transforms a list into another value. As such, this is a perfect place to use a fold.

然而,还有另一种方法来解决你的问题。score函数将列表转换为另一个值。因此,这是一个完美的地方使用折叠。


let score input scorer =
List.fold_left
(fun i x ->
match x with
| "" -> i
| _ -> scorer x + i)
0
input

Now, if we don't need to look for "" values because we've filtered them out, this can be simpler.

现在,如果我们不需要寻找“”值,因为我们已经过滤掉它们,这可以更简单。


let score input scorer =
input
|> List.fold_left (fun i x -> scorer x + i) 0

We can incorporate filtering into this.

我们可以将过滤纳入其中。


let score input scorer =
input
|> List.filter ((<>) "")
|> List.fold_left (fun i x -> scorer x + i) 0

Now, for large data samples, iterating the whole list and creating a new list with List.filter may be onerous, so we can use sequences instead.

现在,对于大型数据样本,使用List.Filter迭代整个列表并创建新列表可能很麻烦,因此我们可以使用序列。


let score input scorer =
input
|> List.to_seq
|> Seq.filter ((<>) "")
|> Seq.fold_left (fun i x -> scorer x + i) 0


I figured out the problem.

我发现了问题所在。


My input.txt actually had empty lines, which caused the String.sub in the scorer function to crash the program. I added a fallback case for an empty string to the function:

我的input.txt实际上有空行,这导致记分器函数中的String.Sub使程序崩溃。我为函数添加了一个空字符串的备用用例:


let scorer s =
let len = String.length s in
if len < 3 then
0
else
let theirs =
match String.sub s 0 1 with
| "A" -> "X"
| "B" -> "Y"
| "C" -> "Z"
| _ -> assert false
in
let ours = String.sub s 2 1 in
let played =
match ours with "X" -> 1 | "Y" -> 2 | "Z" -> 3 | _ -> assert false
in
let result =
match (theirs, ours) with
| "X", "Y" | "Y", "Z" | "Z", "X" -> 6
| theirs, ours when theirs = ours -> 3
| _ -> 0
in
played + result

更多回答

@bennouli incidentally, if that helps you, to find out what the problem is, I loaded the code into an interactive toplevel, then I #trace scorer and I executed the driver code. It showed that scorer was called four times, the last one with the empty string.

@bennouli顺便说一句,如果这能帮助您找出问题所在,我将代码加载到交互式顶层,然后我#跟踪记分器并执行驱动程序代码。它显示该得分手被调用了四次,最后一次调用的是空字符串。

Thanks that's actually very helpful. Did you just copy paste the code into the "utop" REPL with a #trace scorer before the execution of the the functions? I'm trying to find better ways to debug, this is actually a good start.

谢谢,这真的很有帮助。在执行函数之前,你是否只是将代码复制粘贴到“utop”REPL中,并使用#跟踪记分器?我正在努力寻找更好的调试方法,这实际上是一个好的开始。

@bennouli yes, but you could have done that with a regular file and #open "file.ml" or having a text editor that is capable of handling toplevels.

@bennouli是这样的,但是你可以用一个普通的文件和#打开“file.ml”或者有一个能够处理顶层的文本编辑器来做到这点。

You might also simply remove all of the empty lines before processing: let lines = List.filter ((<>) "") @@ read_lines "input.txt" This might be adapted to detect any line which doesn't conform to an expected format.

您也可以在处理之前简单地删除所有空行:let Line=List.Filter((<>)“”)@@Read_Lines“input.txt”这可能适用于检测任何不符合预期格式的行。

I wish standard library functions returned sequences instead of lists (or at least had a sequence counterpart) so that you wouldn't have to choose between efficiency and not reimplementing String.split_on_char or things like that. Otherwise, avoiding useless intermediate lists is really painful.

我希望标准库函数返回的是序列而不是列表(或者至少有一个对应的序列),这样您就不必在效率和不重新实现String.plit_on_char或诸如此类的东西之间做出选择。否则,避免无用的中间列表真的很痛苦。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com