sorawee · GitHub

Many common higher-order functions consume a function value as the first argument, and n more arguments after that, where the function value accepts n arguments, which corresponds to the arguments in the call in some way. Examples include: map, filter (only one argument), andmap, ormap (foldl and foldr have arguments in a wrong order, so they don't quite work)

Example code without pyret-for

(define things     '(("pen") ("pineapple") ("apple") ("pen")))
(define quantities '(1       2             3         5))
(andmap (λ (thing quantity)
          (or (string-contains? (first thing) "apple")
              (odd? quantity)))
        things
        quantities)

The problem is that

  • It's difficult for readers to relate formal arguments of the function value to the actual arguments of the call.
  • There's a lot of rightward drift.

Example code with pyret-for

(define things     '(("pen") ("pineapple") ("apple") ("pen")))
(define quantities '(1       2             3         5))
(pyret-for andmap ([thing things] [quantity quantities])
  (or (string-contains? (first thing) "apple")
      (odd? quantity)))

The pyret-for syntax, based on Pyret's for, can be used to invoke this kind of higher-order functions.

pyret-for additionally improves upon Pyret's for by allowing arbitrary match pattern.

(define things     '(("pen") ("pineapple") ("apple") ("pen")))
(define quantities '(1       2             3         5))
(pyret-for andmap ([(list thing) things] [quantity quantities])
  (or (string-contains? thing "apple")
      (odd? quantity)))

Macro

(require syntax/parse/define)
(define-syntax-parse-rule (pyret-for f:expr ([pat:expr arg:expr] ...) body:expr ...+)
  #:with (x ...) (generate-temporaries (attribute arg))
  (f (λ (x ...)
       (match-define pat x) ...
       body ...)
     arg ...))

Licence

MIT License / CC BY 4.0

Read the original on github.com ↗