Re: How do I use contract combinators to capture optional and rest parameters?

Philip McGrath <philip-HuI0B06iylScIzJqBAPImwC/[email protected]>
Newsgroups gmane.comp.lang.racket.user,gmane.lisp.scheme.plt
Message-ID <CAH3z3gYepErwKWfLPG=fEM7Yg_fOfDY4Lh94UA3RVRJzucsZDA@mail.gmail.com>
Using `case->` can give you the flexibility you want. It works with the
implementation of `my-join` you wrote, but I re-wrote it with `case-lambda`:

#lang racket

(require rackunit)

(define/contract my-join
  (case->
   (-> integer? string?)
   (-> (or/c char? integer?)
       integer?
       #:rest (listof integer?)
       string?))
  (let ()
    (define (do-my-join tokens [delim #\space])
      (string-join (map number->string tokens)
                   (string delim)))
    (case-lambda
      [(int0)
       (do-my-join (list int0))]
      [(char/int . more-ints)
       (if (char? char/int)
           (do-my-join more-ints char/int)
           (do-my-join (cons char/int more-ints)))])))

(check-equal? (my-join #\space 1 2 3) (my-join 1 2 3))


-Philip

On Sat, Jul 28, 2018 at 1:33 PM, Sage Gerard <[email protected]> wrote:

> I am practicing capturing optional parameters and rest parameters in ->*
> while preparing another exercise, with some difficulty.
>
> I wrote a function called my-join that accepts an optional *positional*
> character and then *at least one* integer, returning a string showing the
> string representation of each number separated by the given character. Note
> that (equal? (my-join #\space 1 2 3) (my-join 1 2 3)) should be true. I
> intentionally chose something harder to contract out than it needed to be
> specifically for the subject of the email.
>
> I see two problems in my attempt:
>
>    - The rest-form in the contract disallows applying only one argument
>    to my-join. But if I use just listof, then it's possible to state zero
>    integers with no contract violation.
>    - The let* reinvents optionality for the first argument, but if I use (define
>    [first #\space] . rest) and change ->* to know about the optional
>    param then (my-join 1 2 3) binds first to 1.
>
> Can this contract change to capture all of my stated requirements while
> avoiding the above problems? If so, how? Will follow up early if I figure
> it out.
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;
> #lang racket
>
> (require rackunit)
>
> (define (int-or-char? c) (or (char? c) (integer? c)))
>
> (define/contract (my-join first . rest)
>     (->* (int-or-char?) #:rest (non-empty-listof integer?) string?)
>     (let*
>         ([delim-provided (char? first)]
>         [tokens (if delim-provided rest (cons first rest))]
>         [delim (if delim-provided (make-string 1 first) " ")])
>             (string-join (map number->string tokens) delim)))
>
> (check-equal? (my-join #\space 1 2 3) (my-join 1 2 3))
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/[email protected]
For more options, visit https://groups.google.com/d/optout.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.