在球拍中“减少中锋”?

时间:2019-10-02 14:24:24

标签: functional-programming scheme racket j apl

我正在通过编译器遍历,并且想要删除多余的movq指令。例如,此列表:

((movq a b)
 (movq b c)
 (movq c d)
 (movq d e))

应成为((movq a e))

同样,列表

((movq a b)
 (movq b c)
 (addq 20 c)
 (movq a b)
 (movq c d)
 (movq d e))

应简化为:

((movq a c)
 (addq 20 c)
 (movq a b)
 (movq c e))

如果当前的目标与下一个movq的源匹配,则我的当前(工作)方法将当前和下一个(define (fuse-movq lst) ;; ((movq x y) (movq y z)) => ((movq x z)) (match lst [`(,x) `(,x)] [else (define-values (x z) (values (car lst) (cddr lst))) (match* (x (cadr lst)) [(`(movq ,a ,b) `(movq ,b ,c)) (fuse-movq (cons `(movq ,a ,c) z))] [(_ _) (append (list x) (fuse-movq (cdr lst)))])])) 指令融合在一起。

;; core logic
(define (fuse-movq x y)
  (match* (x y)
    [(`(movq ,a ,b) `(movq ,b ,c)) `(movq ,a ,c)]
    [(_ _) (x y)]))

;; list traversal handled by `foldl`
(foldl fuse-movq '() '((movq a b) (movq b c) (movq c d)))

很好,但是我更希望将逻辑与列表遍历分开,更像这样:

foldl

不幸的是,map似乎不太正确,f也不起作用,因为我要处理“此元素和下一个元素”。

我用APL和J对此进行了标记,因为将中缀函数lst应用于J中的f/\lst的惯用方式是f/。其中apply f between the next 2 elements大致翻译为\,而prefix scanprocessed = 0 starting_after = None while True: results = stripe('get', '/subscriptions', params={ 'limit': 100, 'starting_after': starting_after }).json() for sub in results.get('data'): print("Checking {0} for customer {1}".format(sub.get('id'), sub.get('customer'))) starting_after = sub.get('id') if sub.get('items').get('total_count') != 1: print('Customer {0} has {1} subscriptions ????'.format(sub.get('customer'), sub.get('items').get('total_count'))) continue plan = sub.get('items').get('data')[0].get('plan') if plan.get('id') not in maps: print('Plan {0} was not found'.format(plan.get('id'))) continue try: invoice = stripe('get', '/invoices/upcoming', params={ 'customer': sub.get('customer') }).json() except requests.exceptions.HTTPError as e: if e.response.status_code != 404: print(e.json()) continue print("Ignoring customer {0} because subscription will end ...".format(sub.get('customer'))) continue expected_amount = invoice.get('total') try: new_invoice = stripe('get', '/invoices/upcoming', params={ 'customer': sub.get('customer'), 'subscription': sub.get('id'), 'subscription_items[0][id]': sub.get('items').get('data')[0].get('id'), 'subscription_items[0][deleted]': True, 'subscription_items[1][plan]': maps[plan.get('id')], 'subscription_prorate': False }).json() except Exception as e: print(e.response.json()) continue assert invoice.get('total') == new_invoice.get('total') assert invoice.get('amount_due') == new_invoice.get('amount_due') assert invoice.get('next_payment_attempt') == new_invoice.get('next_payment_attempt') assert invoice.get('period_start') == new_invoice.get('period_start') assert invoice.get('period_end') == new_invoice.get('period_end') stripe('post', '/subscriptions/{0}'.format(sub.get('id')), data={ 'items[0][id]': sub.get('items').get('data')[0].get('id'), 'items[0][deleted]': True, 'items[1][plan]': maps[plan.get('id')], 'prorate': False }).json() updated_invoice = stripe('get', '/invoices/upcoming', params={ 'customer': sub.get('customer') }).json() assert invoice.get('total') == updated_invoice.get('total') assert invoice.get('amount_due') == updated_invoice.get('amount_due') assert invoice.get('next_payment_attempt') == updated_invoice.get('next_payment_attempt') assert invoice.get('period_start') == updated_invoice.get('period_start') assert invoice.get('period_end') == updated_invoice.get('period_end') processed += 1 if not results.get('has_more'): break 。这些语言非常普遍,我希望在Racket中找到类似的习惯用法。

在Racket中,有没有办法将这种“中缀”的功能行为与列表遍历脱钩?

1 个答案:

答案 0 :(得分:1)

您应该能够针对您的用例进行调整。

#lang racket

(define (transform xs)
  (for/fold ([prev (list (first xs))] #:result (reverse prev))
            ([item (in-list (rest xs))])
    (match* (prev item)
      [((list (list p q) xs ...) (list q r)) (cons (list p r) xs)]
      [(xs item) (cons item xs)])))

(transform '([a b] [c d] [d e] [e f] [s t] [g h] [h k] [x y] [y z]))
;=> '((a b) (c f) (s t) (g k) (x z))