-- Leo's gemini proxy

-- Connecting to siiky.srht.site:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

Pipes

siiky

2022/01/09

2022/07/07

en


I've been using my own pipe operators for a while. This is the latest definition:


(define (*=> vals . funs)
  (foldl (lambda (val fun) (fun val))
         (apply (car funs) vals)
         (cdr funs)))

(define ((*-> . funs) . vals)
  (foldl (lambda (val fun) (fun val))
         (apply (car funs) vals)
         (cdr funs)))

(define (=> val . funs)
  (foldl (lambda (val fun) (fun val)) val funs))

(define ((-> . funs) val)
  (foldl (lambda (val fun) (fun val)) val funs))

And this is the original definition (with slightly different semantics):


(define (=*> val funs)
  (foldl (lambda (val fun) (fun val)) val funs))

(define ((-*> funs) val)
  (=*> val funs))

(define (=> val . funs)
  (=*> val funs))

(define ((-> . funs) val)
  (=*> val funs))

Comparing with Scheme's `o`:


(o snd fst)
(-> fst snd)

There's no equivalent to Scheme's `compose`.


I've never used =*> and -*> directly (they're there just in case, and as the base for the other two), but I've grown attached to -> and =>.


The reasoning behind the names is simple: think of a function as a "processing pipe". -> is a chain of such pipes, and a pipe on its own, without "contents" -- you have to plug something on one end to get something on the other end. On the other hand, => already has the stuff plugged in, ready to go, so it's fatter.


Some uses:


(map (-> do-this
         and-that)
     some-list)

(=> some-list
    (cute map (-> do-this and-that) <>)
    (cute filter (o not screwed?) <>))

((-> (cute map (-> do-this and-that) <>)
     (cute filter (o not screwed?) <>))
   some-list)

(filter (o not screwed?)
        (map (-> do-this and-that)
             some-list))

(-> do-this and-that) is an unary function -- that's why it can be given to map.


(=> some-list ...) evaluates to a value, which is the result of applying the filter to the result of applying the map to some-list.


The third and fourth expressions, ((-> ...) some-list) and (filter ...), are equivalent to the second.


Note the use of o instead of -> in the filter's predicate. Personal preference, but I think that case reads better with o because it's more like English.


-----


But now that'll probably be the end of them for me.


Yesterday I learned of SRFI-197 -- very cool! There's even an egg for CHICKEN already.


SRFI-197

SRFI-197 egg


And I can rename the exported identifiers to the ones I've been using:


(import
  chicken.module
  (rename
    (only srfi-197
          chain
          chain-lambda)
    (chain =>)
    (chain-lambda ->)))

With that, the previous example is written like so:


(map (-> (do-this _)
         (and-that _))
     some-list)

(=> some-list
    (map (-> (do-this _) (and-that _)) _)
    (filter (o not screwed?) _))

((-> (map (-> (do-this _) (and-that _)) _)
     (filter (o not screwed?) _))
   some-list)

(filter (o not screwed?)
        (map (-> (do-this _) (and-that _))
             some-list))

Maybe the advantage(s) aren't obvious (maybe they're not advantages at all!),

but to me not having to write `cute` for non-unary functions is a plus, even if

I'm now forced to write parenthesis and an underscore on every unary function.


I guess the only situation(s) I don't see myself using it is if I want to avoid

dependencies.

-- Response ended

-- Page fetched on Mon May 13 18:07:50 2024