【问题标题】:Create suffixed numbers Racket创建后缀数字球拍
【发布时间】:2018-11-29 17:01:24
【问题描述】:

我正在尝试在 Racket 中做些什么,我想在数字后面加上字母。

对于这个例子,我只想将10000 表示为10K,将1000000 表示为1M

有没有办法(使用宏或其他方式)我可以将1M 扩展为:

(* 1 1000000)

或者类似的东西?

【问题讨论】:

    标签: numbers racket


    【解决方案1】:

    在 Racket 中,10K 之类的东西是标识符,通常是指变量。有两种方法可以将它们变成数字:

    1:重新定义“未定义”标识符的含义

    您可以通过定义 #%top 宏来重新定义对未定义标识符执行的操作。

    #lang racket
    (require syntax/parse/define
             (only-in racket [#%top old-#%top]))
    
    (define-syntax-parser #%top
      [(_ . x:id)
       #:when (id-has-a-k-at-the-end? #'x)
       (transform-id-into-number #'x)]
      [(_ . x)
       #'(old-#%top . x)])
    

    但是,这有一个微妙的问题。如果您的程序中有任何标识符或变量以 K 结尾,它们可以覆盖任何以这种方式编写的数字。您需要注意不要意外覆盖本来是数字的内容。

    2:制作一个阅读器扩展,将它们变成数字而不是标识符

    这将花费更多时间,但它更接近执行此操作的“正确方法”,因为它避免了当变量恰好有 K 结尾时发生冲突。

    扩展阅读器的一种更简单的方法是使用readtable。您可以创建一个扩展 readtable 的函数,如下所示:

    ;; Readtable -> Readtable
    (define (extend-readtable orig-rt)
      ;; Char InputPort Any Nat Nat Nat -> Any
      (define (rt-proc char in src ln col pos)
        ....)
      ...
      (make-readtable orig-rt
        #f 'non-terminating-macro rt-proc
        ...))
    

    要使用它来定义#lang 语言,您需要将阅读器实现放在your-language/lang/reader.rkt 中。这里是number-with-k/lang/reader.rkt,其中number-with-k 目录安装为单一集合包(raco pkg install path/to/number-with-k)。

    number-with-k/lang/reader.rkt

    #lang racket
    
    (provide (rename-out [-read read]
                         [-read-syntax read-syntax]
                         [-get-info get-info]))
    
    (require syntax/readerr
             syntax/module-reader)
    
    ;; Readtable -> Readtable
    (define (extend-readtable orig-rt)
      ;; Char InputPort Any Nat Nat Nat -> Any
      (define (rt-proc char in src ln col pos)
        ....)
      ...
      (make-readtable orig-rt
        #f 'non-terminating-macro rt-proc))
    
    ;; [X ... -> Y] -> [X ... -> Y]
    (define ((wrap-reader rd) . args)
      (parameterize ([current-readtable (extend-readtable (current-readtable))])
        (apply rd args)))
    
    (define-values [-read -read-syntax -get-info]
      (make-meta-reader 'number-with-k
                        "language path"
                        lang-reader-module-paths
                        wrap-reader
                        wrap-reader
                        identity))
    

    主要工作是填补extend-readtable函数中的....漏洞。例如,您可以让它识别以K 结尾的标识符,如下所示:

    ;; Readtable -> Readtable
    (define (extend-readtable orig-rt)
      ;; Char InputPort Any Nat Nat Nat -> Any
      (define (rt-proc char in src ln col pos)
        (define v (read-syntax/recursive src in char orig-rt #f))
        (cond
          [(and (identifier? v) (id-has-a-k-at-the-end? v))
           (transform-id-into-number v)]
          [else
           v]))
    
      (make-readtable orig-rt
        #f 'non-terminating-macro rt-proc))
    

    完成此操作后,您将number-with-k 目录安装为一个包,您应该可以像这样使用#lang number-with-k

    #lang number-with-k racket
    
    (+ 12K 15)
    ; => 12015
    

    【讨论】:

    • 我也想到了#%top,你可以使用identifier-binding来检查标识符是否已经有绑定——如果有,你可能想跳过转换。
    • identifier-binding 检查不足以避免这些问题,因为如果定义了标识符,它首先不会调用 #%top
    【解决方案2】:

    最简单的方法是定义你需要的后缀。

    (define K 1000)
    (define M 1000000)
    

    然后写(* 3.14 M) 314 万。

    正如其他人提到的,Racket 支持科学计数法3.14E6 也是 314 万。

    另一种选择是定义函数KM 等,例如:

    (define (M x) (* x 1000000))
    

    那你就可以写了

    (M 3.14)
    

    意思是 314 万。

    【讨论】:

      【解决方案3】:

      Racket 已经有built in support for this, kind of,通过科学记数法:

      1e6 ; 1000000.0 ("1M")
      2e7 ; 20000000.0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-12
        • 2015-04-08
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        • 2019-01-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多