首页 > 解决方案 > Racket:在函数中使用“csv-reading”包

问题描述

我正在使用csv-reading从 csv 文件中读取以将其转换为列表。

当我在顶层调用时,像这样

> (call-with-input-file "to-be-asked.csv" csv->list)

我能够读取 csv 文件并将其转换为列表列表。

但是,如果我在函数中调用相同的东西,我会收到错误消息。

> (read-from-file "to-be-asked.csv")
csv->list: undefined;
 cannot reference an identifier before its definition
  in module: top-level

我不明白出了什么问题。我(require csv-reading)在函数调用之前添加了。

我的read-from-file代码是:

(define (read-from-file file-name)
  (call-with-input-file file-name csv->list))

编辑

我在 usingracketemacs使用Geiser。当我(exit)缓冲区和类型C-c C-z时,它显示错误。

当我杀死缓冲区并重新启动Geiser时,它工作正常。是Geiserand的错误emacs吗?

标签: csvemacsracketgeiser

解决方案


您遇到了我称之为常驻编程环境的经典问题(当时我不知道正确的词)。常驻编程环境是您与正在运行的语言实例对话,连续修改其状态的环境。

这些环境的问题在于,正在运行的语言实例的状态或多或少是不透明的,特别是它可能与您在文件或缓冲区中看到的状态不同步。这意味着它可能会变得晦涩难懂,更糟糕的是,您可能会进入从常驻环境中获得的结果在以后基本上无法重现的状态。这对于像 Jupyter notebook 这样的东西来说很重要,在这些东西中,从事科学工作的人最终可能会得到他们无法重现的结果,因为 notebook 的评估顺序不正确,或者其中一些根本没有评估。

另一方面,这些环境使用起来非常愉快,这就是我使用它们的原因。这对我来说比问题更重要:你只需要小心你可以重新创建会话并愿意偶尔这样做。

在这种情况下,您可能在缓冲区/文件中有类似的内容:

(require csv-reading)

(define (read-from-file file-name)
  (call-with-input-file file-name csv->list))

但是您要么根本没有评估第一个表格,要么(更糟糕的是!)您无序地评估了表格。如果你在 Common Lisp 或任何传统的 Lisp 中这样做,这一切都很好:评估第一种形式将使第二种形式工作。但是 Racket 在定义时一劳永逸地决定什么csv->list意思(或不意味着什么),read-from-file以后provide不会解决这个问题。然后,您最终会陷入您定义的函数不起作用的神秘情况,但是如果您定义了一个使用它的函数,它将起作用。这是因为它具有比 CL 更聪明的语义,但据我所知,它的语义也不是为这种交互式开发设计的(当然 DrRacket 强烈反对它)。csv->list


推荐阅读