Scheme 并行使用两个列表并返回其中一个列表的其余部分的设计模式

Scheme 并行使用两个列表并返回其中一个列表的其余部分的设计模式,scheme,idioms,Scheme,Idioms,摘要:抽象问题是: 价值清单 修饰符列表,作用于值以返回新值的内容 (对于示例代码,我只是将值乘以修饰符值) 修改器列表不受限制为与值列表相同的大小 将修改器应用于值,并返回所有未使用的修改器 这是一个使用两个独立函数的版本:一个用于实际应用修饰符,一个用于获取其余修饰符 ;; Return the modified list (define (apply-mods vals mods) (if (or (null? vals) (null? mods)) vals (

摘要:抽象问题是:

  • 价值清单
  • 修饰符列表,作用于值以返回新值的内容 (对于示例代码,我只是将值乘以修饰符值)
  • 修改器列表不受限制为与值列表相同的大小
  • 将修改器应用于值,并返回所有未使用的修改器
这是一个使用两个独立函数的版本:一个用于实际应用修饰符,一个用于获取其余修饰符

;; Return the modified list
(define (apply-mods vals mods) 
    (if (or (null? vals) (null? mods)) vals
      (cons (* (car vals) (car mods)) (apply-mod (cdr vals) (cdr mods)))
    )
)
;; trim the modifiers 
(define (trim-mods vals mods)
    (if (or (null? vals) (null? mods)) mods
    (trim-mods (cdr vals) (cdr mods))
)
我的想法是,在应用修改器列表后,
(apply mods vals mods)
我可能希望使用剩余的修改器 后续操作中的修饰符
(微调模块VAL mods)

目前,我提出的最好的方法是双函数方法,但是在列表中迭代两次似乎是浪费

是否有一种干净的方法来返回修改后的值和未使用的修改器

具体问题是:

  • 我的价值观是音符;每个都有一个卷和一个持续时间。比如:
    (第1卷,第1拍)(第1卷,第2拍)(第1卷,第1拍)
  • 我的修饰符是“更改音量”,每个修饰符都有音量更改和持续时间
    (dvol:+1 dur:4拍)(dvol:-2 dur:4拍).
  • 当我在列表中递归时,我会跟踪净累积时间,以确定哪个修饰符对给定的音符有效
因此,在实际问题中,修饰符与值之间不存在简单的1-1映射,因此我希望遇到这样的情况,即我将修饰符列表应用于比注释列表更短的注释列表(就持续时间而言);然后我想申请
下一个音符列表的剩余修饰符(我计划将整个音乐分割成块)。

假设这些是预期的结果:

> (apply-mods '((1 . 10)) '((1 . 4) (2 . 4) (3 . 4)))
'((2 . 4) (3 . 4) (4 . 2))
'((3 . 2))

> (apply-mods '((1 . 1) (1 . 2) (1 . 1)) '((+1 . 4) (-2 . 4)))
'((2 . 1) (2 . 2) (2 . 1))
'((-2 . 4))
这是一个简单的循环,并行处理2个列表:

(define (apply-mods vals mods)
  (let loop ((vals vals) (mods mods) (res null))
    (cond
      ((null? vals) (values (reverse res) mods))
      ((null? mods) (error "not enough mods"))
      (else
       (let ((val (car vals)) (mod (car mods)))
         (let ((vol (car val)) (dur (cdr val)) (dvol (car mod)) (ddur (cdr mod)))
           (cond
             ; case 1. duration of note = duration of mod => consume note and mod
             ((= dur ddur)
              (loop (cdr vals) 
                    (cdr mods) 
                    (cons (cons (+ vol dvol) dur) res)))
             ; case 2. duration of note < duration of mod => consume note, push back shorter mod
             ((< dur ddur) 
              (loop (cdr vals) 
                    (cons (cons dvol (- ddur dur)) (cdr mods)) 
                    (cons (cons (+ vol dvol) dur) res)))
             ; case 3. duration of note > duration of mod => push back part of note, consume mod
             (else         
              (loop (cons (cons vol (- dur ddur)) (cdr vals)) 
                    (cdr mods) 
                    (cons (cons (+ vol dvol) ddur) res))))))))))
(定义(应用mods VAL mods)
(let循环((VAL VAL)(mods mods)(res null))
(续)
((空?VAL)(值(反向分辨率)mods))
((null?mods)(错误“mods不足”))
(其他
(let((val(car vals))(mod(car mods)))
让(音量(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(音量)(
(续)
;案例1.注释持续时间=修改持续时间=>使用注释和修改
(=dur-ddur)
(循环(cdr VAL)
(cdr mods)
(cons(cons(+vol-dvol)dur)res)))
;案例2.音符持续时间消耗音符,向后推较短的mod
(mod的持续时间=>音符的后推部分,使用mod
(其他
(循环(cons(cons vol(-dur ddur))(cdr vals))
(cdr mods)
(反对(反对(+vol dvol)ddur)res()()()())()()(())())41

您的要求似乎更简单,您可能只需要介绍案例1,但我只能在等待示例时进行推测。在任何情况下,您都可以很容易地根据您的特定需要调整此代码。

听起来您可能需要一个可变的数据结构,例如队列

(make-mod-queue '(dvol: +1 dur: 4 beats)(dvol: -2 dur: 4 beats)...))

#queue((4 (dvol: +1)) (4 (dvol: -2)) ...)

(make-note-queue '(vol: 1, dur: 1 beat)(vol: 1 dur: 2 beats)(vol: 1 dur: 1 beat))

#queue((1 (vol" 1)) (1 (vol: 1)) (2 (vol: 1))
然后创建一个函数来组合它们

(define (apply-mods note-queue mod-queue)
 (let ((new-queue make-empty-queue))
       (get-note-dur (lambda () 
                      (if (emtpy-queue? note-queue)
                          #f  
                          (car (front-queue note-queue)))))
       (get-mod-dur (lambda () 
                      (if (empty-queue? mod-queue)
                          #f
                          (car (front-queue mod-queue)))))
       (get-vol 
          (lambda () 
            (if (or (empty-queue? mod-queue) (empty-queue? mod-queue))
                 #f        
                 (+ (note-vol (front-queue note-queue)) 
                    (mod-vol  (front-queue mod-queue)))))))
   (let loop ((d1 (get-note-dur)) ;;should return #f is note-queue is empty
              (d2 (get-mod-dur))  ;;ditto for mod-queue
              (vol (get-volume))) 
    (cond ((not vol) 
           (cond ((and d2 (not (= d2 (get-mod-dur))))
                  (set-car! (front-queue mod-queue) d2) new-queue)
                  new-queue)
                 ((and d1 (not (= d1 (get-note-dur))))
                  (set-car! (front-queue note-queue) d1) new-queue)
                  new-queue)
                 (else new-queue)))
          ((= d1 d2)
           (insert-queue! new-queue (cons d1 (list 'vol: vol)))
           (delete-queue! note-queue)
           (delete-queue! mod-queue)
           (loop (get-note-dur) (get-mod-dur) (get-volume)
          ((< d1 d2)
           (insert-queue! new-queue (cons d1 (list 'vol: vol)))
           (delete-queue! note-queue)
           (loop (get-note-dur) (- d2 d1) (get-volume)))
          ((> d1 d2)
           (insert-queue! new-queue (cons d2 (list 'vol: vol)))
           (delete-queue! mod-queue)
           (loop (- d1 d2) (get-mod-dur) (get-volume)))))))
(定义(应用mods注释队列mod队列)
(让((新队列变为空队列))
(获取注释dur(lambda()
(如果(emtpy队列?注释队列)
#f
(汽车(前排队列注释队列(())))
(获取mod dur(lambda()
(如果(空队列?修改队列)
#f
(车辆(前排队列模块队列(()())))
(获取卷
(lambda()
(如果(或(空队列?修改队列)(空队列?修改队列))
#f
(+(注释卷(前排注释队列))
(mod vol(前端队列mod queue(()()())))
(let循环((d1(get note dur));应返回#如果note队列为空
(d2(get mod dur));;mod queue同上
(卷(获取卷)))
(cond(非vol)
(cond((和d2(不(=d2(得到mod dur))))
(设置车辆!(前排队列修改队列)d2)新队列)
新队列)
((和d1(非(=d1(在dur中获取注释)))
(设置车辆!(前排队列注释队列)d1)新队列)
新队列)
(否则为新队列)))
(=d1-d2)
(插入队列!新队列(cons d1(列表'vol:vol'))
(删除队列!注意队列)
(删除队列!修改队列)
(循环(获取注释dur)(获取模块dur)(获取音量)
(d1和d2)
(插入队列!新队列(cons d2(列表'vol:vol)))
(删除队列!修改队列)
(循环(-d1-d2)(获取模块dur)(获取卷()()()()))))
会回来吗 #队列(1(第二卷))(1(第二卷))(第二卷) 以及您的mod队列(无论您传入了什么,现在都会变异为 #队列(4(dvol:-2)), 原来的票据队列现在是一个空队列

SICP中描述的队列


如果下一个音符的持续时间大于下一个修改器的持续时间,即当一个音符需要由2个或更多的修改器进行部分处理时,您是否需要提供下一个音符的持续时间?否:我使用的是更像“下一个音符开始前的时间间隔”的音符持续时间“。在音符开头生效的修饰语就是要应用的修饰语。好的,我