This is very cool. You might take a look at the `threading` module for additional ideas: https://docs.racket-lang.org/threading/index.html
On Tue, Mar 9, 2021 at 10:20 AM Roger Keays <[email protected]> wrote: > Hi all, > > I recently publish a new package called *fluent* which adds some syntax > enhancements to Racket. Links and README below. Let me know what you > think... > > Roger > > https://pkgs.racket-lang.org/package/fluent > https://github.com/rogerkeays/racket-fluent/ > > # fluent > > UNIX style pipes and a lambda shorthand syntax to make your Racket code > more readable. > > ## ? Unpopular So LISP Is Why > > Let's be honest. LISP missed a huge opportunity to change the world by > telling developers they have to think backwards. Meanwhile, UNIX became > successful largely because it allows you to compose programs sequentially > using pipes. Compare the difference (the LISP example is actually racket): > > UNIX: cat data.txt | grep "active" | cut -f 4 | uniq | sort > LISP: (sort (remove-duplicates (map (λ (line) (list-ref (string-split > line) 4)) ((filter (λ (line) (string-contains? line "active")) (file->lines > "data.txt")))))) > > Using *fluent*, the same racket code can be written according to the UNIX > philosophy: > > ("data.txt" > file->lines >> filter (line : line > string-contains? > "active") >> map (line : line > string-split > list-ref 4) > > remove-duplicates > sort) > > You can use unicode → instead of > if you prefer. It is more distinctive > and a bit easier on the eyes: > > ("data.txt" → file->lines →→ filter (line : line → string-contains? > "active") →→ map (line : line → string-split → list-ref 4) → > remove-duplicates → sort) > > ## Function Composition > > Using the function composition operator (> or →), *fluent* inserts the > left hand side as the first parameter to the procedure on the right hand > side. Use >> (or →→) to add the left hand side as the last parameter to the > procedure. > > (data > procedure params) becomes (procedure data params) > (data >> procedure params) becomes (procedure params data) > > This operation can be chained or nested as demonstrated in the examples. > > ## Lambda Shorthand > > The : operator allows you to easily write a lambda function with one > expression. Parameters go on the left, the expression on the right, no > parentheses required. For example: > > > ((x : + x 1) 1) > 2 > > ((x y : + x y) 1 2) > 3 > > (map (x : string-upcase x) '("a" "b" "c")) > '("A" "B" "C") > > ## Math Procedures > > Since this library uses > for function composition, the built in > greater-than procedure is renamed to `gt?`. Note, this could break existing > code if you are already using the > procedure. Other math procedures are > also renamed for consistency, and because the text versions read more > naturally when using function composition. > > > gt? > < lt? > >= gte? > <= lte? > + add > - subtract > * multiply > / divide > > ## Convenience Procedures > > *fluent* works best when the data (input) parameter comes first. Most > racket functions do this out of the box, but many functions which take a > procedure as a parameter put the data last. That's fine, because you can > just use >>. Alternatively you can wrap and rename the procedure, which is > what we've done for these functions: > > original data-first version > ----------------------------- > for-each iterate > > example: > > > ('(1 2 3) → iterate (x : displayln x)) > 1 > 2 > 3 > > ## Comparison to Clojure's Threading Macro > > Clojure's threading macro is a prefix operator, which means it is less > readable when nested and requires more parentheses. You could say that the > *fluent* infix operator acts as one parenthesis. Compare: > > CLOJURE (prefix): > > (-> (list (-> (-> id3 (hash-ref 'genre "unknown")) normalise-field) > (-> (-> id3 (hash-ref 'track "0")) normalise-field) > (-> (-> id3 (hash-ref 'artist "unknown")) normalise-field) > (-> (-> id3 (hash-ref 'title "unknown")) normalise-field)) > (string-join ".")) > > FLUENT (infix): > > (list (id3 → hash-ref 'genre "unknown" → normalise-field) > (id3 → hash-ref 'track "0" → normalise-field) > (id3 → hash-ref 'artist "unknown" → normalise-field) > (id3 → hash-ref 'title "unknown" → normalise-field)) → > string-join ".") > > Fluent's infix approach also makes it easier to combine thread-first (→) > with thread-last (→→). > > ## How to enter → with your keyboard > > → is Unicode character 2192. On linux you can enter this using > `shift-ctrl-u 2192 enter`. Naturally, if you want to use this character, > you should map it to some unused key on your keyboard. This can be done > with xmodmap: > > # use xev to get the keycode > $ xev > > # check the current mapping > $ xmodmap -pke > > # replace the mapping > $ xmodmap -e "keycode 51=U2192 Ccedilla ccedilla Ccedilla braceright > breve braceright" > > Making this change permanent depends on your session manager. Search > duckduckgo for details. > > ## Installation > > This library is available from the Racket package collection and can be > installed with raco: > > $ raco pkg install fluent > > All you need to do is `(require fluent)`. You can try it out in the REPL: > > > (require fluent) > > ("FOO" > string-downcase) > "foo" > > ((x y : x > add y) 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 [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/racket-users/sigid.1702887e81.20210309152029.GA3105%40papaya.papaya > . > -- 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 [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/CAE8gKod-vE2H2bS%3DJGmVc%3DQa-CmrsZYvfbx1cJsoLWRhfVKfww%40mail.gmail.com.

