gpt4 book ai didi

racket - 如何扩展 Racket 的阅读器以获得更好的路径处理?

转载 作者:行者123 更新时间:2023-12-05 03:14:28 24 4
gpt4 key购买 nike

我一直致力于将我用 Python 编写的静态站点生成器转换为 Racket。这主要是为了更好地了解 Racket 的学习练习。我现在可以使用 Racket 版本,但有一点我更喜欢 Python 版本:pathlib.Path 对象。生成器有很多路径处理,在 Python 代码中看起来是这样的:

render_template(root / "templates" / "index.jinja")

而 Racket 代码看起来更像这样:

(render-template (build-path (root) "templates" "index.jinja"))

我发现在 Python 代码中读取路径的能力更清晰,所以我想修改 Racket 阅读器以支持如下内容:

(render-template (root) / "templates" / "index.jinja")

和读者一起玩,我想出了如何让这种表达起作用:

(render-template  / foo / templates / index.jinja /)

我可以接受语法,但我不知道如何将路径元素作为 Racket 表达式求值,而不仅仅是字符串。即使我确实弄清楚了,我仍然有一个问题,即简单的字符串处理会导致类似以下问题:

(render-template / (root) / (string-join 
(list "templates" "subdir") "/")
/ "index.jinja" /)

那么,关于我在这里可以做什么,有什么建议/意见吗? :)

最佳答案

如果我没理解错的话,原来你有这样的东西:

(define (root)
"/")

(define (render-template path)
(displayln path))

(render-template (build-path (root) "templates" "index.jinja"))
;; => /templates/index.jinja

我的建议是简单地改变 render-template 这样它就可以用多个路径“部分”调用——它处理调用build-path 给你:

(define (render-template . path-parts)
(define path (apply build-path path-parts))
(displayln path))

现在你可以这样调用它:

(render-template (root) "templates" "index.jinja")
;; => /templates/index.jinja

顺便说一句,原来的方式仍然有效,因为build-path 在这种情况下将充当标识:

(render-template (build-path (root) "templates" "index.jinja"))
;; => /templates/index.jinja

我认为这是最“骚”的方式。关于一件好事s-expressions 是您不必键入“分隔符”,如 /。空格就够了。而且我认为你阅读和编写 Racket 代码的次数越多,你越会有这种感觉。

诚然,也许最令人不安的事情就是能够你自己的小(或大)语言。如果你想要一个“DSL”来写主要由路径组成的文件,这可能是一回事。但在在这种情况下,我不确定我是否看到了巨大的胜利。


如果有的话,也许您只需要一个宏这使得 / 在此上下文中充当空格。即到使 / 在扩展代码中意味着它最终需要成为的“无”。

例如:

#lang racket/base

(require (for-syntax racket/base syntax/parse))

(define-syntax (render-template stx)
(define-splicing-syntax-class pp
(pattern (~seq part (~optional (~literal /)))))
(syntax-parse stx
[(_ p:pp ...) #'(do-render-template p.part ...)]))

(define (do-render-template . path-parts)
(define path (apply build-path path-parts))
(displayln path))

(render-template (root) / "templates" / "index.jinja")
;; => /templates/index.jinja
(render-template (root) "templates" "index.jinja")
;; => /templates/index.jinja

请注意,/ 在这里是完全可选的。他们被视为空格。

另请注意,真正的工作是在函数中完成的,现在重命名为 do-render-template。宏只是一个包装器。一般来说,宏最好尽可能少地做必要的工作,可以是函数的东西最好是函数。

但同样,我个人不会为宏而烦恼,我会采用上面建议的方法。


更新:附言,如果我理解正确,Python 的PathLib.Path/ 定义为运算符?好吧,Racket 并没有真正的“运营商”。它有功能。像 / 这样的数学函数接受任意数量的参数。因此,我们编写 (/10 5 2) 而不是 10/5/2。实际上,这让我们绕了一圈又回到了 build-path:一个包含任意数量路径部分的函数。

我想您可以有效地将 build-path 重命名为 /:

(require (rename-in (except-in racket /)
[build-path /]))
(/ (root) "templates" "index.jinja")

但这并不是真正的运算符重载,因为它们是普通函数而不是方法。而且……我不会那样做。 :)

关于racket - 如何扩展 Racket 的阅读器以获得更好的路径处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24462913/

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