如何在 Scheme 中仅使用 1 个列表来构建 2 个列表?

How to build 2 lists using only 1 list in Scheme?

我正在尝试做一个将字符列表作为输入的函数,returns一个包含条件中给定特定字符之前的所有字符的列表,以便我可以计算后缀表达式.

示例:用户输入字符串" 5 =b 10 * =c "

我做的第一步是使用 string->list 将此字符串转换为列表,所以我得到这样的列表

(# #\space #\=#\b #\space # #\space #\* #\space #\=#\c #\space)

然后我开始阅读列表,一旦我阅读了字符 #\= 就停止了,我将它之前的所有字符放在 list1 中,然后是字符之后的所有内容 list2。 所以我得到 list1 (#) 并且 list2(#\b #\space # #\space #\* #\space #\=#\c #\space)

然后我将 5 分配给 b(car list2),然后继续阅读 list2 直到我阅读另一个 =,然后我将第二个 = 之前的所有元素放在列表中 (#\b #\space # #\space #\*) 的列表中,然后我计算 b * 10 ,并将结果存储在 c 这是第一个元素最后一个列表。

这个函数是我写的

(define affect
  (lambda(l1 l2 l3)
    (cond ((null? l1)'())
          ((eq? (car l1) #\=)(append(cons (cdr l1)l2)))
          (else (affect (cdr l1)(cons(car l1)l2)l3)))))

但似乎这并不是我真正想要的,而且一切都变得越来越复杂...有什么想法吗?只是提出一个想法如何解决这样的问题。

你没有提到你使用的是哪种实现,所以我将使用我最熟悉的 Racket。

一些备注:

  • 我不明白你为什么要在这里管理变量,因为它们还没有被使用
  • 这是一个 RPN 计算器,因此您需要有某种堆栈(列表在这里非常方便)
  • 我宁愿在这里使用字符串而不是字符

我使用 命名的 let 创建了一个工作实现,这是我将在此处使用的循环结构。我也在使用 let* 和 Racket 的一些方便的程序,如 substringstring-split。我不知道你是否被允许使用这些,但你总是可以自己创建它们。

所以这是一个示例实现,它既不完整也不万无一失,但它正确地处理了您的示例输入:

(define (evaluate str)
  (let loop ((lst (string-split str)) ; named let for looping
             (stack '())
             (vars '()))
    (printf "lst=~v  stack=~a  vars=~a\n" lst stack vars) ; display, for debugging purposes
    (if (null? lst)
        (car stack)  ; done, return top of stack
        (let* ((c  (car lst))           ; element to process
               (n  (string->number c))  ; try to convert c to a number; returns #f if ko
               (op (string->symbol c))) ; convert c to a symbol
          ; recursive call to loop
          (loop
           ; first element is replaced by rest of list
           (cdr lst)
           ; second element is the (updated) stack
           (cond
             (n           (cons n stack))
             ((eq? op '*) (cons (* (first stack) (second stack)) (cddr stack)))
             (else        stack))
           ; third element is the (updated) list of variables
           (if (string=? (substring c 0 1) "=")
               (cons (list (substring c 1) (car stack)) vars)
               vars))))))

display 将显示中间结果:

> (evaluate "5 =b 10 * =c ")
lst='("5" "=b" "10" "*" "=c")  stack=()  vars=()
lst='("=b" "10" "*" "=c")  stack=(5)  vars=()
lst='("10" "*" "=c")  stack=(5)  vars=((b 5))
lst='("*" "=c")  stack=(10 5)  vars=((b 5))
lst='("=c")  stack=(50)  vars=((b 5))
lst='()  stack=(50)  vars=((c 50) (b 5))
50

编辑

这是一个使用字符列表的版本。我添加了一个额外的列表 token 来收集要处理的字符。每当需要处理令牌时,我都会将其转换回可接受的字符串。

我还添加了一个辅助函数 cdr0,它非常方便,不会使对 loop 的递归调用完全不可读:

(define (evaluate str)
  (define (cdr0 lst) (if (null? lst) lst (cdr lst))) ; helper: skip one element if the list is not yet empty
  (let loop ((lst (string->list str)) (token '()) (stack '()) (vars  '()))
    (printf "lst=~v  token=~v  stack=~a  vars=~a\n" lst token stack vars) ; display, for debugging purposes
    (cond
      ; end of processing -> return top of stack, we're done
      ((and (null? token) (null? lst)) (car stack))
      ; end of word or end of list -> process
      ((and (or (null? lst) (eqv? (car lst) #\space))
            (not (null? token)))
       (let* ((token-string (list->string (reverse token)))
              (n            (string->number token-string)))  ; try to convert c to a number; returns #f if ko
         (cond
           ; number
           (n
            (loop (cdr0 lst) '() (cons n stack) vars))
           ; variable assignment
           ((string=? (substring token-string 0 1) "=")
            (loop (cdr0 lst) '() stack (cons (list (substring token-string 1) (car stack)) vars)))
           ; multiplication
           ((string=? token-string "*")
            (loop (cdr0 lst) '() (cons (* (first stack) (second stack)) (cddr stack)) vars))
           ; none of these
           (else (error "wot?")))))
      (else
       (loop (cdr lst) (cons (car lst) token) stack vars)))))

测试:

> (evaluate "5 =b 10 * =c")
lst='(# #\space #\= #\b #\space # #[=13=] #\space #\* #\space #\= #\c)  token='()  stack=()  vars=()
lst='(#\space #\= #\b #\space # #[=13=] #\space #\* #\space #\= #\c)  token='(#)  stack=()  vars=()
lst='(#\= #\b #\space # #[=13=] #\space #\* #\space #\= #\c)  token='()  stack=(5)  vars=()
lst='(#\b #\space # #[=13=] #\space #\* #\space #\= #\c)  token='(#\=)  stack=(5)  vars=()
lst='(#\space # #[=13=] #\space #\* #\space #\= #\c)  token='(#\b #\=)  stack=(5)  vars=()
lst='(# #[=13=] #\space #\* #\space #\= #\c)  token='()  stack=(5)  vars=((b 5))
lst='(#[=13=] #\space #\* #\space #\= #\c)  token='(#)  stack=(5)  vars=((b 5))
lst='(#\space #\* #\space #\= #\c)  token='(#[=13=] #)  stack=(5)  vars=((b 5))
lst='(#\* #\space #\= #\c)  token='()  stack=(10 5)  vars=((b 5))
lst='(#\space #\= #\c)  token='(#\*)  stack=(10 5)  vars=((b 5))
lst='(#\= #\c)  token='()  stack=(50)  vars=((b 5))
lst='(#\c)  token='(#\=)  stack=(50)  vars=((b 5))
lst='()  token='(#\c #\=)  stack=(50)  vars=((b 5))
lst='()  token='()  stack=(50)  vars=((c 50) (b 5))
50