3

Is it possible to have piping in Racket with output of one function going to next. For example, can following code be rewritten:

(define (safestr sentstr)
   (list->string
    (remove*
     (list   #\| #\;  #\:  #\/ #\\ #\' #\")
     (string->list sentstr) )))

(define  (safestr sentstr)
  sentstr | 
  (string->list .) |
  (remove* (list #\: #\;) .) |
  (list->string .) )

Where "." indicates output of previous statement.

This also shows normal direction of flow and progress rather than reverse flow.

Racket being language to create languages should be able to do this. I checked here https://docs.racket-lang.org/reference/pipeports.html but could not find how to do this.

Thanks for your comments/answers.

rnso
  • 23,686
  • 25
  • 112
  • 234
  • I have no idea why this was downvoted... – molbdnilo Aug 12 '16 at 08:41
  • 1
    Jargon note, though: the word "output" is almost never used to refer to a function's result or return value, and there are no "statements" in Scheme or Racket. Googling for those words probably won't bring good results. – molbdnilo Aug 12 '16 at 08:41

1 Answers1

7

Yes, actually, though the syntax is rather different from what you have listed. The threading package implements precisely this sort of thing, borrowed from Clojure’s threading macros. Using threading, your function would look like this:

(require threading)

(define (safestr sentstr)
  (~>> sentstr
       string->list
       (remove* (list #\| #\; #\: #\/ #\\ #\' #\"))
       list->string))

Take a look at the documentation for ~>> for more information.

You could also use λ~>> to eliminate the need to name the argument entirely:

(require threading)

(define safestr
  (λ~>> string->list
        (remove* (list #\| #\; #\: #\/ #\\ #\' #\"))
        list->string))

There’s also the point-free package, which implements similar functionality using higher-order functions rather than macros. When paired with a lambda shorthand package like curly-fn, the result ends up looking quite similar to the versions using threading without needing to use macros:

#lang curly-fn racket/base

(require point-free)

(define safestr
  (λ~> string->list
       #{remove* (list #\| #\; #\: #\/ #\\ #\' #\")}
       list->string))
Alexis King
  • 43,109
  • 15
  • 131
  • 205
  • 1
    With threading, why there are no () around string->list and list->string, while there are around remove*. Is it because there are no other arguments with first two? – rnso Aug 12 '16 at 07:12
  • 1
    @rnso Yes, that’s correct. The documentation for `threading` explains in more detail. – Alexis King Aug 12 '16 at 07:20
  • Can you include statements which do not use previous output and still let that pass to next line? For example, can you include a line with (println "here") after "string->list" line ? – rnso Aug 12 '16 at 08:57
  • 1
    You could do that with the first or second example by inserting `(begin (println "here") _)`, or with the third example by inserting `#{begin (println "here") %)`. Both basically create effect-ful identity functions to thread together – Alex Knauth Aug 12 '16 at 14:03