Hypothetical Syntax Time

Hi, Racket Discourse.

I was browsing the examples of the proposed conditional syntax in this paper, The Ultimate Conditional Syntax.

I have not read the formal claims and proofs they make, but the shape of things is intriguing, and it got me wondering about what I would like from the "ultimate conditional".

Arguably, match and friends, not to forget the behemoth, cond, are already more than any programmer might ask for; it is, however, fun to speculate.

So, stealing some ideas from the paper, and without stating that this is necessarily better, I would propose something like this:

; cond-case, which is like `cond`
(choose
 [is (blue? x) and is (red? y)
  then (orange)]
 
 [is (red? x) and is (blue? y)
  then (purple)]
 
 [else (yellow)])

; match-case, which is like `match`
(choose
 [(choose
   [is (odd? a) then (list 1 2)]
   [else             (list 2 1)]
  ) is (list x y)
  and
  b is (list u v)
  then (list x u)]
 
 [(choose
   [is (even? a) then (cons 1 2)]
   [else              (cons 2 1)]
  ) is (cons x y)
  and
  b is (cons u v)
  then (list y v)]
 
 [else (list a b)])

The basic form of choose is:

(choose <branch> ...+)

where <branch> is of the form [<case> then <result>], or possibly in the final branch, of the form [else <result>]. Finally, each <case> is of the form <clause> {and <clause>} .... The <result> would be the same as with cond and so on.

Each <clause> can be one of two flavors:

  • is x (where x is either true-thy or false)
  • x is y (where x is some value and y is a match pattern)

What I like about this, is that it reads quite easily (in these simple cases) and it combines cond and match quite elegantly, but it seems like it could become a soup of words quite quickly.


Edit: what about plurals, eh?

(choose
 [are (even? x y z) then 'all-even])
; is synonym to something like
(choose
 [is (even? x) and is (even? y) and is (even? z) then 'all-even])

(choose
 [(x y z) are ((? integer?) (? symbol?) (? string?))
  then 'integer-symbol-string])
; is synonym to
(choose
 [x is (? integer?) and y is (? symbol?) and z is (? string?)
  then 'integer-symbol-string])

Edit: and then you could specialize on the verb! Latin, anyone?

(choose
 [is-list (even? xs) then 'all-even])
; is synonym to
(choose
 [xs is (list (? even?) ...) then 'all-even])

Edit: instead

(choose
  [is list of (blue? '(blue blue blue))
   then 'blues]
  [else
   'sunshine])
;=> 'blues

which expands into a for/and in terms of the <type> to range over, being list in this case, thus:

(for/and ([tmp (in-list vals)]) (pred? tmp))

What do you think about this, and more interestingly, what would your fantasy conditional look like, if any?


Edit: chef's kiss


Edit: it's alive!

1 Like

Enough faffing about with the original post; I apologize if this is poor taste, I have been having quite the blast.

#lang racket

(require rackunit choose)

(check-equal?
 (choose
   [is (integer? 1) then 'integer]
   [else
    #false])
 'integer
 "cond-like: `is` <subject>")

(check-equal?
 (choose
   [are (integer? 1 2 3) then 'integers]
   [else
    #false])
 'integers
 "cond-like: `are` <subjects>")

(define x #s(node inside))
(check-equal?
 (choose
   [x is `#s(node ,inside) then inside]
   [else
    #false])
 'inside
 "match-like: <subject> `is` <object>")

(define y #s(node 100))
(define z #s(node "string"))
(check-equal?
 (choose
   [(x y z) are (`#s(node ,(? symbol?))
                 `#s(node ,(? integer?))
                 `#s(node ,(? string?)))
    then 'symbol-integer-string]
   [else
    #false])
 'symbol-integer-string
 "match-like: <subjects> `are` <objects>")

(check-equal?
 (choose
   [is   #true]
   [else #false])
 (void)
 "omitting the result-body returns `(void)`")

(check-equal?
 (choose
   [is #:not #false]
   [else     #false])
 (void)
 "using `#:not` negates the condition")

(check-equal?
 (choose
   [are #:not (exact? 1 2 3.0) then 'not-all-exact]
   [else
    #false])
 'not-all-exact
 "the `#:not` distributes in the plural case for cond-like behaviour")

(check-equal?
 (choose
   [('(1) '(1 2) '(3 . 4))
    are #:not
    (`(,x) `(,y ,z) `(,u . ,v))
    then 'never-reached]
   [else
    'otherwise])
 'otherwise
 "the `#:not` distributes in the plural case for match-like behaviour, too")

(check-equal?
 (choose
   ['(when-the-going-gets-tough)
    is (list item) #:when (symbol? item)
    then 'we-write-DSLs]
   [else
    #false])
 'we-write-DSLs
 "when-conditions work like they do in `match`")

(define a-sequence '(basically for loops!))
(check-equal?
 (choose
   [is list #:of (symbol? a-sequence)
    then a-sequence]
   [else
    #false])
 '(basically for loops!)
 "using `#:of <type>` causes the predicate to be sequenced over the <subject>")

(define x-seq '(bas ica lly))
(define y-seq #(f o r))
(define z-seq '(lo op s!))
(check-equal?
 (choose
   [are (list   #:of (symbol? x-seq))
        (vector #:of (symbol? y-seq))
        (list   #:of (symbol? z-seq))
    then a-sequence]
   [else
    #false])
 '(basically for loops!)
 "`#:of ...` distributes over plural <subjects>, as well")

(define u-seq (list 1 2 3))
(check-equal?
 (choose
   [are #:not
        (list   #:of (symbol? x-seq)
         vector #:of (symbol? u-seq)
         list   #:of (symbol? z-seq))
    then a-sequence]
   [else
    #false])
 '(basically for loops!)
 "`#:of ...` can be grouped (and negated) for plural <subjects>")
  
(check-equal?
 (choose
   [are   (list #:of (symbol? x-seq))
    #:not (list #:of (symbol? u-seq))
          (list #:of (symbol? z-seq))
    then a-sequence]
   [else
    #false])
 '(basically for loops!)
 "`#:of ...` can modify the condition over individual <subjects>")

(define some-strings '("one" "two" "buckle my shoe"))
(check-equal?
 (choose
   [is #:of (#:type list? #:over in-list)
       (string? some-strings)
    then
    'it-still-works-baby!]
   [else
    #false])
 'it-still-works-baby!
 "`#:of ...` plays nice, if you ask it to")

(check-equal?
 (choose
   [is #:of (#:over in-list)
    (string? some-strings) ; hopefully this is a list
    then
    'it-still-works-baby!]
   [else
    #false])
 'it-still-works-baby!
 "`#:of ...` can be risky, though")

(check-equal?
 (choose
   [is (integer? 1)     and
    is (symbol? 'hello) and
    is (string? "world")]
   [else
    #false])
 (void)
 "multiple <clauses> can be joined with `and`")
  
(define spicy-curry
  (choose (x y z) (u v w)
    [is (odd?  x) and
     is (even? y) and
     is (odd?  z)
     then (list x y z)]
    [else (list u v w)]))
(check-equal?
 ((spicy-curry 1 0 1) 1 1 1)
 '(1 0 1)
 "you know it's gonna come out cursed on the other end")

Edit: haha upside-down tests; checks out...