You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Racket for循环报application: not a procedure错误排查与实现

Racket通用CSV转Prolog子句实现方案

报错根因

触发application: not a procedure; expected a procedure that can be applied to arguments错误的核心原因是代码括号匹配/迭代逻辑错误:

  • Racket为前缀语法,括号位置错误会直接改变执行逻辑:你写的嵌套循环大概率在按索引取谓词、取单元格值时多写/漏写括号,把从列表中取出的字符串、符号类值(比如谓词名、单元格内容)放在了过程调用的位置,Racket尝试将这些非过程值当函数执行,直接抛出该错误。
  • 普通嵌套for循环会生成两个列表的笛卡尔积,不符合“每行单元格与同位置谓词一一匹配”的需求,且基础for迭代不会自动累积生成的Prolog子句到结果列表中。
  • 原有逐列手写when判断的硬编码方案与CSV表头结构强耦合,列名、列数、列顺序调整时必须修改源码,编码量大且极易出现拼写错误。

实现思路

完全解耦CSV结构与代码逻辑:

  1. 先读取CSV第一行作为表头,自动生成/匹配每一列对应的Prolog谓词列表,和列位置一一对应
  2. 逐行遍历数据行,并行遍历当前行的单元格与对应位置的谓词,自动生成Prolog子句
  3. 统一处理Prolog语法格式(特殊原子加引号、数字直接输出)
  4. 所有子句生成完成后一次性写入目标pl文件

样例参考

  • 测试用women.csv内容:
name,age,occupation,nationality
Alice,30,teacher,American
Bella,25,designer,Canadian
  • 期望输出的females-by-Racket.pl内容:
name(alice, 'Alice').
age(alice, 30).
occupation(alice, teacher).
nationality(alice, 'American').
name(bella, 'Bella').
age(bella, 25).
occupation(bella, designer).
nationality(bella, 'Canadian').

可直接运行的通用代码

依赖Racket官方csv-reading库,可通过raco pkg install csv-reading安装:

#lang racket
(require csv-reading)

;; 路径配置
(define input-csv-path "women.csv")
(define output-pl-path "females-by-Racket.pl")
;; 自定义谓词映射:键为CSV表头名,值为对应Prolog谓词名,未配置的列默认用表头小写作为谓词
(define custom-predicate-map (hash))

;; 读取CSV内容
(define csv-reader (make-csv-reader (open-input-file input-csv-path)))
(define all-rows (csv->list csv-reader))
(define header-row (first all-rows))
(define data-rows (rest all-rows))

;; 生成与列位置一一对应的谓词列表
(define predicate-list
  (for/list ([col-name (in-list header-row)])
    (string->symbol (hash-ref custom-predicate-map col-name (string-downcase col-name)))))

;; 值转合法Prolog项:数字直接输出,纯小写原子直接输出,其他内容加单引号包裹
(define (to-prolog-term val)
  (cond
    [(string->number val) val]
    [(regexp-match #rx"^[a-z][a-zA-Z0-9_]*$" val) val]
    [else (format "'~a'" val)]))

;; 生成所有Prolog子句
(define all-clauses
  (for*/list ([row (in-list data-rows)]
              ;; 跳过全空的无效行
              #:when (not (andmap string-empty? row))
              ;; 默认第一列为姓名,转小写作为事实的第一个参数
              [person-id (in-value (to-prolog-term (string-downcase (first row))))]
              ;; 并行遍历谓词列表和当前行单元格,一一对应不生成笛卡尔积
              [(pred cell-val) (in-parallel (in-list predicate-list) (in-list row))])
    (format "~a(~a, ~a)." pred person-id (to-prolog-term cell-val))))

;; 写入结果到Prolog文件,存在则覆盖
(with-output-to-file output-pl-path
  (lambda () (for-each displayln all-clauses))
  #:exists 'replace)

使用注意事项

  • 并行遍历两个等长列表必须使用in-parallel,否则会出现笛卡尔积错误,生成大量不符合预期的子句。
  • 如果第一列不是姓名字段,只需修改person-id的取值逻辑即可,不需要改动其他遍历代码。
  • 如果CSV列数变动、列名调整,不需要修改核心遍历逻辑,只需在custom-predicate-map中补充特殊列的谓词映射即可。
  • 写代码时可借助DrRacket的括号高亮功能检查括号配对,从根源避免“值被当过程调用”的语法错误。

内容的提问来源于stack exchange,提问作者John Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 09:57:18