-
Notifications
You must be signed in to change notification settings - Fork 15
Define identity elements for -< and ==* and name some flows.
#70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5c01192
ad78814
9618e10
37b7e14
c0506bc
063cd21
8f6eca0
f74b270
845aa79
f429750
c75b979
9ad9257
ee6b1f8
575b27f
b5ea1c0
46aed9f
88a7406
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,10 @@ | |
| map-values | ||
| filter-values | ||
| partition-values | ||
| 1->1 | ||
| *->1 | ||
| relay | ||
| tee | ||
| loom-compose | ||
| parity-xor | ||
| arg | ||
|
|
@@ -40,22 +43,22 @@ | |
|
|
||
| ;; we use a lambda to capture the arguments at runtime | ||
| ;; since they aren't available at compile time | ||
| (define (loom-compose f g [n #f]) | ||
| (let ([n (or n (procedure-arity f))]) | ||
| (define (loom-compose f g [n (procedure-arity f)]) | ||
| (define compiled-group-flow | ||
| (λ args | ||
| (let ([num-args (length args)]) | ||
| (if (< num-args n) | ||
| (if (= 0 num-args) | ||
| (values) | ||
| (error 'group (~a "Can't select " | ||
| n | ||
| " arguments from " | ||
| args))) | ||
| (let ([sargs (take args n)] | ||
| [rargs (drop args n)]) | ||
| (apply values | ||
| (append (values->list (apply f sargs)) | ||
| (values->list (apply g rargs)))))))))) | ||
| (define num-args (length args)) | ||
| (if (< num-args n) | ||
| (if (= 0 num-args) | ||
| (values) | ||
| (error 'group (~a "Can't select " | ||
| n | ||
| " arguments from " | ||
| args))) | ||
| (let-values ([(sargs rargs) (split-at args n)]) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice 👌
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm considering if it's necessary to optimize (group 0 *->1 f) ; f
(group 0 1->1 f) ; f
(group +inf.0 f g) ; f
(group +inf.f f g) ; fIn addition, it seems that |
||
| (apply values | ||
| (append (values->list (apply f sargs)) | ||
| (values->list (apply g rargs)))))))) | ||
| compiled-group-flow) | ||
|
|
||
| (define (parity-xor . args) (and (foldl xor #f args) #t)) | ||
|
|
||
|
|
@@ -165,7 +168,7 @@ | |
| [b (in-value (cdr c+b))] | ||
| [args (in-value (hash-ref by-cs c))]) | ||
| (call-with-values (λ () (apply b args)) list))) | ||
| (apply values (apply append results))) | ||
| (apply values (append* results))) | ||
|
|
||
| (define (->boolean v) (and v #t)) | ||
| (define true. (thunk* #t)) | ||
|
|
@@ -186,6 +189,9 @@ | |
| (append (values->list (apply op vs)) | ||
| (apply zip-with op (map rest seqs)))))) | ||
|
|
||
| (define 1->1 (thunk (values))) | ||
| (define *->1 (thunk* (values))) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you explain the notation here? It doesn't seem to indicate the number of values since the first is 0->0, and the second is N->0.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These appear in error messages shown to the user: Any reason not to use
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On the one hand, I haven't thought of a better notation for
For example, > (eq? (☯ ⏚) (☯ (-<)))
#tAnd if we rename these procedures, the equality will be lost.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for clarifying! The correspondence to category theory and the duality between sum and product makes sense, but do you anticipate any particular advantage gained by having the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, in general functions are undecidable. But Welcome to Racket v8.6 [cs].
> (require qi)
> (define (f) 123)
> (eq? f (☯ (-< (-<) f)))
#t
> (eq? f (☯ (-< f (-<))))
#tI prefer to preserve the properties of mathematical structures as much as possible.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I agree that we should aim to preserve mathematical properties. Yet, Aside from the specific choice of equality relation, in the present case, I feel the mathematical properties we'd like to preserve are: That is, an operational equivalence in terms of the result of applying these functions to arguments. Since, for instance, we could have a totally different definition of Btw, I also meant that code in general should not do checks like
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think For example, I thought about simulating the limit in category theory by inserting procedures between the arguments of (define do (make-parameter values))
(~> f g h ...) ; = (~> f (do) g (do) h (do) ...)But it affects the performance of And on the other hand, I'm not sure if it's a good idea to rename the returned procedures in any case. If we rename > ((procedure-rename add1 'compiled-tee-flow) 1 2 3)
compiled-tee-flow: arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 3
[,bt for context]
> ((let ([compiled-tee-flow (lambda args (apply add1 args))]) compiled-tee-flow) 1 2 3)
add1: arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 3
[,bt for context]The 1st way might be consistent with the way you expect to rename > (~> (1 2 3) (-< add1 sub1))
add1: arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 3
[,bt for context]I'm not sure if renaming named functions (like
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related thoughts:
|
||
|
|
||
| ;; from mischief/function - requiring it runs aground | ||
| ;; of some "name is protected" error while building docs, not sure why; | ||
| ;; so including the implementation directly here for now | ||
|
|
@@ -194,9 +200,26 @@ | |
| (lambda (ks vs f . xs) | ||
| (keyword-apply f ks vs xs)))) | ||
|
|
||
| (define (relay . fs) | ||
| (λ args | ||
| (apply values (zip-with call fs args)))) | ||
| (define relay | ||
| (case-lambda | ||
| [() 1->1] | ||
| [(f) (procedure-reduce-arity-mask f 2)] | ||
| [fs | ||
| (define (compiled-relay-flow . args) | ||
| (apply values (zip-with call fs args))) | ||
| compiled-relay-flow])) | ||
|
|
||
| (define (tee . fs) | ||
| (match (remq* (list *->1) fs) | ||
| ['() *->1] | ||
| [`(,f) f] | ||
| [fs | ||
| (define (compiled-tee-flow . args) | ||
| (apply values | ||
| (append* | ||
| (for/list ([f (in-list fs)]) | ||
| (values->list (apply f args)))))) | ||
| compiled-tee-flow])) | ||
|
|
||
| (define (all? . args) | ||
| (and (for/and ([v (in-list args)]) v) #t)) | ||
|
|
@@ -208,7 +231,7 @@ | |
| (not (for/or ([v (in-list args)]) v))) | ||
|
|
||
| (define (repeat-values n . vs) | ||
| (apply values (apply append (make-list n vs)))) | ||
| (apply values (append* (make-list n vs)))) | ||
|
|
||
| (define (power n f) | ||
| (apply compose (make-list n f))) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not able to verify the original behavior here at the moment, but does this PR modify the behavior of any edge cases, e.g.
(fanout 0)or(gen), or(relay)? If it does, it would be great to add tests for these cases. For cases like(fanout 0)and(fanout 1)we would need tests even if the behavior hasn't changed since it would now hit different code that needs to be covered by tests (unfortunately the coverage check on PRs doesn't work at the moment, but you can runmake coverto generate a coverage report locally).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR doesn't modify the original behavior, I will write more tests later.