Repository navigation
pyret-for - a new way to call higher order functions #11
Description
Activity
Great idea! I really like how small the macro is.
I wonder if we can think of a clearer name. I like that
pyret-forgives credit to Pyret and gives a hint about one good way to use this macro (for-style loops). But it doesn't say much about what's really going on ... and if we understood that, maybe we'd find other ways to use this macro.polydot-apply?
map-comprehension?Reacted by Ben GreenmanI'm not sure what "polydot" means.
comprehensioncould work, I think. I would avoidmap-, since it supports more thanmap.Oh, "polydot" is the local name for the polymorphic dotted (
...) types that work for typingmapfoldetc. [1]. Typed Racket uses that name internally [link]. I don't know where else to find it in print.Anyway, I was thinking that polydot-typed functions have something in common that makes them fit well with
pyret-for.But looking back at your original message, I see that
filteralso works well withpyret-for. So I guess "polydot" is too specific.[1] Practical Variable Arity Polymorphism. ESOP 2009
Today I explained this
pyret-formacro to a few people at Brown. While thinking about it, we came up with one way to generalize:(apply/lambda f (arg-spec ...) body ...) where arg-spec is one of: - #:hole - #:from [id expr] - expr and the sequence (arg-spec ....) has exactly one #:hole expands to: (let ((g (lambda (id ...) body ...))) (apply f (convert/g arg-spec) ...)) where convert/g: - replaces #:hole with g - replaces #:from [id expr] with expr - and leaves other expr aloneI like
#:holea lot. That'd help this macro work withfoldl.The other (non-
#:from) arguments would be inputs tofthat don't get passed along to the newly-built lambda.Like this?
#lang racket (require syntax/parse/define (for-syntax racket/match racket/list)) (begin-for-syntax (define-syntax-class arg-spec #:attributes ([tmp-id 1] gen-match-code expr) (pattern #:proc #:with (tmp-id ...) #'() #:with gen-match-code #'(begin) #:with expr #'the-function) (pattern [pat:expr #:from expr:expr] #:with (tmp-id ...) (generate-temporaries (list #'id)) #:with gen-match-code #'(begin (match-define pat tmp-id) ...)) (pattern expr:expr #:with (tmp-id ...) #'() #:with gen-match-code #'(begin))) (define (validate-proc-once args) (define proc-list (filter (λ (arg) (equal? '#:proc (syntax-e arg))) (syntax->list args))) (match (length proc-list) [1 #f] [0 args] [_ (first proc-list)]))) (define-syntax-parse-rule (apply/λ f:expr {~and args (arg:arg-spec ...+)} body:expr ...+) #:fail-when (validate-proc-once #'args) "#:proc must appear exactly once" (let ([the-function (λ ({~@ arg.tmp-id ...} ...) arg.gen-match-code ... body ...)]) (f arg.expr ...))) (apply/λ andmap (#:proc [(list x) #:from '((1) (2) (3))] [y #:from '(3 2 1)]) (even? (+ x y))) (define (hof offset xs proc) (+ offset (apply + (map proc xs)))) (apply/λ hof (100 [x #:from '(1 2 3)] #:proc) (* 2 x))foldlandfoldrunfortunately still couldn't be expressed with this generalization.Ah! I didn't mean to make you implement it --- I thought we were just talking about possibilities.
That's awful about fold. I guess I'd want
#:procto take an (optional?) arg to give the order of parameters, but that screws up the match-define ....;; ... something like this (apply/λ foldl (#:proc (x* y acc) [acc #:from 0] [(list x) #:id x* #:from '((1) (2) (3))] [y #:from '(3 2 1)]) (+ x y acc))😞
Actually, my version above also has a bug. I should check
'paren-shapefor[<x> #:from <y>]. Otherwise, a function application(some-function #:from 123)will be parsed as aapply/λbinding.- added a commit that references this issue
on Oct 10, 2021 - added 2 commits that reference this issue
on Oct 27, 2021
Many common higher-order functions consume a function value as the first argument, and
nmore arguments after that, where the function value acceptsnarguments, which corresponds to the arguments in the call in some way. Examples include:map,filter(only one argument),andmap,ormap(foldlandfoldrhave arguments in a wrong order, so they don't quite work)Example code without
pyret-forThe problem is that
Example code with
pyret-forThe
pyret-forsyntax, based on Pyret'sfor, can be used to invoke this kind of higher-order functions.pyret-foradditionally improves upon Pyret'sforby allowing arbitrarymatchpattern.Macro
Licence
MIT License / CC BY 4.0