I am struggling to understand how the -> and ->> expand.
If I have the following:
(-> query
(write-query-to-excel db csv-file)
(archiver archive-password)
(send-with-attachment send-to subject body)
(clean-up))
How does this expand, I understand that -> is a thread-first macro which inserts the the value as the second item as the first form, and after looking at examples I'm still unsure.
Also how does ->> differ, I know it inserts the item as the last argument of the function but again the wording confuses me.
(->> query
(write-query-to-excel db csv-file)
(archiver archive-password)
(send-with-attachment send-to subject body)
(clean-up))
When expanded how would these two macros look?
-> and ->> always remind me of Matryoshka dolls because they nest all expressions passed to them.
Let's consider (-> a (b c d) (e f g)). We can now visually cut them (with a pipe) at the 1st argument position in each expression but the first: (-> a (b | c d) (e | f g)). Now that the expressions are cut in halves we can nest them: first (-> (b a c d) (e | f g)) and then (-> (e (b a c d) f g)) which simplifies to (e (b a c d) f g).
->> works in a very similar manner except the insert point is at the end (last argument position): (-> a (b c d |) (e f g |)) which successively expands to (-> (b c d a) (e f g |)), (-> (e f g (b c d a))) and (e f g (b c d a)).
Using clojure.walk/macroexpand to expand the macros:
(clojure.walk/macroexpand-all '(-> query
(write-query-to-excel db csv-file)
(archiver archive-password)
(send-with-attachment send-to subject body)
(clean-up)))
... produces
(clean-up (send-with-attachment (archiver (write-query-to-excel query db csv-file) archive-password) send-to subject body))
Whereas
(clojure.walk/macroexpand-all '(->> query
(write-query-to-excel db csv-file)
(archiver archive-password)
(send-with-attachment send-to subject body)
(clean-up)))
... produces
(clean-up (send-with-attachment send-to subject body (archiver archive-password (write-query-to-excel db csv-file query))))
Since the result doesn't have to make sense, we can use simpler examples to illustrate the difference:
(clojure.walk/macroexpand-all '(-> a b c d))
;(d (c (b a)))
, the same with -> or ->>. But if there are arguments:
(clojure.walk/macroexpand-all '(-> a (b 1 2 3)))
;(b a 1 2 3)
whereas
(clojure.walk/macroexpand-all '(->> a (b 1 2 3)))
;(b 1 2 3 a)
The answer from #cgrand is good, but I would like to add a bit more.
You could achieve something very similar by putting your thread-first example into a (let...) form as:
; better if descriptive names used for intermediate results
(let [tmp1 (write-query-to-excel db csv-file)
tmp2 (archiver tmp1 archive-password)
tmp3 (send-with-attachment tmp2 send-to subject body)
tmp4 (clean-up tmp3) ]
<process result in tmp4>
...)
This is often the best solution since you can use descriptive variable names for the intermediate results. If, however, you won't really benefit from naming the intermediate results, you can use a generic variable it as a placeholder and still see exactly where each intermediate result is used in the next form. This is how the it-> macro from the Tupelo Core library works:
Imagine using a variable it to mark the location in each form where the result of the previous expression is inserted. Then in your -> example, we get:
(ns my.proj
(:require [tupelo.core :refer [it->]]
... ))
(it-> (write-query-to-excel db csv-file)
(archiver it archive-password)
(send-with-attachment it send-to subject body)
(clean-up it))
Then in your ->> example we would have:
(it-> (write-query-to-excel db csv-file)
(archiver archive-password it)
(send-with-attachment send-to subject body it)
(clean-up it))
However, what do we do if the expressions do not all chain together in either the first or last argument position? Consider this code:
(it-> 1
(inc it)
(+ it 3)
(/ 10 it)
(str "We need to order " it " items." )
;=> "We need to order 2 items." )
In this case, we have expressions where the previous result is chained into the only, first, last, and middle argument positions. In this case, neither -> nor ->> will work, and one must use something like it-> or a generic (let ...) form.
So for simple expression pipelines, using it-> (or the similar as->) can make the code more explicit about how the expressions are chained together. It also allows you to chain expressions that are not all "thread-first" or "thread-last". For more complicated processing chains, using a let form (possible nested) is the best answer as you can name the intermediate results and then combine them in arbitrarily complicated ways.
Would you mind taking a little tour around programming languages?
Ruby
In the world of Ruby there is a common practice of making so-called "method chains". What it is, essentially, is:
calling a method
calling a method on its result
calling a method on that method's result
etc.
Ruby is object-oriented, and such chains look like this:
(-5..5).map(&:abs)
.select(&:even?)
.count
.to_s
take a range of integers from -5 to 5 inclusive
map them into their absolute values
only select those that are even
count how many you have
convert the resuling number into a string
In Ruby, collections are objects, methods like map, count and select are their methods. map returns a collection, on which you can call select. On the result of select we call count that outputs an integer. Then we call to_s on that integer to convert it into a string. The dot-call of object.method calls a method on an object. Familiar stuff.
In some languages you may be exposed to terrible truth that object's methods may be nothing but a simple function that takes an object it acts upon and arguments. Some languages thoroughly hide that fact as an implementation detail, but could that convention actually be a limitation?
Lua
Lua is a nice little and honest language that doesn't hide from you what object's methods are. Consider these two equivalent lines:
obj.increase(obj, 5)
obj:increase(5)
It's a convention enforced on language-level: a method is a function that takes its owner object as a first argument.
...and some others with "static extension"
Defining all the possibly needed methods in a type has proven to be impossible, so some languages have adopted "static extension": it allows you to create a function that takes an "object acted upon" as its first argument (without access to sources of the type itself!). Then with some syntactic sugar you can use x.ext(y) calls instead of ext(x, y):
C# has that.
Haxe has that.
C++ doesn't have that, but there are proposals to add this, that highlight the semantic similarities of x.f(y) and f(x, y)
That feature allows us to chain operations a slightly cleaner way.
g(f(x, y), z) # Before
x.f(y).g(z) # After
Clojure
And we're back! So what does all this have to do with -> and ->>? They provide similar-looking syntax that looks good in longer chains.
We know for sure that our map and filter (same as Ruby's select) are just functions that take collections they act upon as their last (oops, that was unexpected!) argument.
(->> (range -5 6) (map #(Math/abs %)) ; 6 not included
(filter even?)
(count)
(str))
Oh, so we see a bit different way here: functions we treat as methods here take an object they act upon as their last argument. But we just make the "chain" using ->> and that fact becomes less noticeable.
If we had functions that took "object acted upon" as their first argument, as we've seen in Lua, we'd use ->. Depending on the functions you're chaining, -> might make more sense.
We can have it both ways, we can even mix them with a tad more verbose as->.
Related
How can I assert that 2012/08 (instead of Aug 2012) is returned from this function?
Thus I can start learning lisp on the job/with the function itself until the output satisfies.
I know some python unit testing (pytest) and am looking for something similar for lisp. However, my first attempt[0] C-c eval-buffer fails with Invalid function: "<2012-08-12 Mon>"
(assert (= (org-cv-utils-org-timestamp-to-shortdate ("<2012-08-12 Mon>")) "Aug 2012"))
(defun org-cv-utils-org-timestamp-to-shortdate (date_str)
"Format orgmode timestamp DATE_STR into a short form date.
Other strings are just returned unmodified
e.g. <2012-08-12 Mon> => Aug 2012
today => today"
(if (string-match (org-re-timestamp 'active) date_str)
(let* ((abbreviate 't)
(dte (org-parse-time-string date_str))
(month (nth 4 dte))
(year (nth 5 dte))) ;;'(02 07 2015)))
(concat
(calendar-month-name month abbreviate) " " (number-to-string year)))
date_str))
[0] https://www.emacswiki.org/emacs/UnitTesting
(assert (= (org-cv-utils-org-timestamp-to-shortdate ("<2012-08-12 Mon>"))
"Aug 2012"))
(defun org-cv-utils-org-timestamp-to-shortdate (...) ...)
statements are executed in sequence, which means your function will only be defined after the assertion is evaluated. This is a problem because the assertion calls that function. You should reorder your code to test it after the function is defined.
you cannot compare strings with =, if you call describe-function (C-h f) for =, you'll see that = is a numerical comparison (in fact, numbers or markers). For strings you need to use string=.
In a normal evaluation context, ie. not in a macro or a special form, the following is read as a function call:
("<2012-08-12 Mon>")
Parentheses are meaningful, the above form says: call function "<2012-08-12 Mon>" with zero arguments. This is not what you want, there is no need to add parentheses here around the string.
In clojure you can create anonymous functions using #
eg
#(+ % 1)
is a function that takes in a parameter and adds 1 to it.
But we also have to use # for regex
eg
(clojure.string/split "hi, buddy" #",")
Are these two # related?
There are also sets #{}, fully qualified class name constructors #my.klass_or_type_or_record[:a :b :c], instants #inst "yyyy-mm-ddThh:mm:ss.fff+hh:mm" and some others.
They are related in a sence that in these cases # starts a sequence recognisible by clojure reader, which dispatches every such instance to an appropriate reader.There's a guide that expands on this.
I think this convention exists to reduce the number of different syntaxes to just one and thus simplify the reader.
The two uses have no (direct) relationship.
In Clojure, when you see the # symbol, it is a giant clue that you are "talking" to the Clojure Reader, not to the Clojure Compiler. See the full docs on the Reader here: https://clojure.org/reference/reader.
The Reader is responsible for converting plain text from a source file into a collection of data structures. For example, comparing Clojure to Java we have
; Clojure ; Java
"Hello" => new String( "Hello" )
and
[ "Goodbye" "cruel" "world!" ] ; Clojure vector of 3 strings
; Java ArrayList of 3 strings
var msg = new ArrayList<String>();
msg.add( "Goodbye" );
msg.add( "cruel" );
msg.add( "world!" );
Similarly, there are shortcuts that the Reader recognizes even within Clojure source code (before the compiler converts it to Java bytecode), just to save you some typing. These "Reader Macros" get converted from your "short form" source code into "standard Clojure" even before the Clojure compiler gets started. For example:
#my-atom => (deref my-atom) ; not using `#`
#'map => (var map)
#{ 1 2 3 } => (hash-set 1 2 3)
#_(launch-missiles 12.3 45.6) => `` ; i.e. "nothing"
#(+ 1 %) => (fn [x] (+ 1 x))
and so on. As the # or deref operator shows, not all Reader Macros use the # (hash/pound/octothorpe) symbol. Note that, even in the case of a vector literal:
[ "Goodbye" "cruel" "world!" ]
the Reader creates a result as if you had typed:
(vector "Goodbye" "cruel" "world!" )
Are these two # related?
No, they aren't. The # literal is used in different ways. Some of them you've already mentioned: these are an anonymous function and a regex pattern. Here are some more cases:
Prepending an expression with #_ just wipes it from the compiler as it has never been written. For example: #_(/ 0 0) will be ignored on reader level so none of the exception will appear.
Tagging primitives to coerce them to complex types, for example #inst "2019-03-09" will produce an instance of java.util.Date class. There are also #uuid and other built-in tags. You may register your own ones.
Tagging ordinary maps to coerce them to types maps, e.g. #project.models/User {:name "John" :age 42} will produce a map declared as (defrecord User ...).
Other Lisps have proper programmable readers, and consequently read macros. Clojure doesn't really have a programmable reader - users cannot easily add new read macros - but the Clojure system does internally use read macros. The # read macro is the dispatch macro, the character following the # being a key into a further read macro table.
So yes, the # does mean something; but it's so deep and geeky that you do not really need to know this.
I am wondering if it is possible to apply Regex-like pattern matching to keys in a plist.
That is, suppose we have a list like this (:input1 1 :input2 2 :input3 3 :output1 10 :output2 20 ... :expand "string here")
The code I need to write is something along the lines of:
"If there is :expand and (:input* or :output*) in the list's keys, then do something and also return the :expand and (:output* or :input*)".
Obviously, this can be accomplished via cond but I do not see a clear way to write this elegantly. Hence, I thought of possibly using a Regex-like pattern on keys and basing the return on the results from that pattern search.
Any suggestions are appreciated.
Normalize your input
A possible first step for your algorithm that will simplify the rest of your problem is to normalize your input in a way that keep the same information in a structured way, instead of inside symbol's names. I am converting keys from symbols to either symbols or lists. You could also define your own class which represents inputs and outputs, and write generic functions that works for both.
(defun normalize-key (key)
(or (cl-ppcre:register-groups-bind (symbol number)
("^(\\w+)(\\d+)$" (symbol-name key))
(list (intern symbol "KEYWORD")
(parse-integer number)))
key))
(defun test-normalize ()
(assert (eq (normalize-key :expand) :expand))
(assert (equal (normalize-key :input1) '(:input 1))))
The above normalize-key deconstructs :inputN into a list (:input N), with N parsed as a number. Using the above function, you can normalize the whole list (you could do that recursively too for values, if you need it):
(defun normalize-plist (plist)
(loop
for (key value) on plist by #'cddr
collect (normalize-key key)
collect value))
(normalize-plist
'(:input1 1 :input2 2 :input3 3 :output1 10 :output2 20 :expand "string here"))
=> ((:INPUT 1) 1
(:INPUT 2) 2
(:INPUT 3) 3
(:OUTPUT 1) 10
(:OUTPUT 2) 20
:EXPAND "string here")
From there, you should be able to implement your logic more easily.
I'm new to Clojure and found there's a piece of code like following
user=> (def to-english (partial clojure.pprint/cl-format nil
"~#(~#[~R~]~^ ~A.~)"))
#'user/to-english
user=> (to-english 1234567890)
"One billion, two hundred thirty-four million, five hundred sixty-seven
thousand, eight hundred ninety"
at https://clojuredocs.org/clojure.core/partial#example-542692cdc026201cdc326ceb. I know what partial does and I checked clojure.pprint/cl-format doc but still don't understand how it translates an integer to English words. Guess secret is hidden behind "~#(~#[~R~]~^ ~A.~)" but I didn't find a clue to read it.
Any help will be appreciated!
The doc mentions it, but one good resource is A Few FORMAT Recipes from Seibel's Practical Common Lisp.
Also, check §22.3 Formatted Output from the HyperSpec.
In Common Lisp:
CL-USER> (format t "~R" 10)
ten
~#(...~^...) is case conversion, where the # prefix means to capitalize (upcase only the first word). It contains an escape upward operation ~^, which in this context marks the end of what is case-converted. It also exits the current context when there are no more argument available.
~#[...] is conditional format: the inner format is applied on a value only if it is non nil.
The final ~A means that the function should be able to accept one more argument and print it.
In fact, your example looks like the one in §22.3.9.2:
If ~^ appears within a ~[ or ~( construct, then all the commands up to
the ~^ are properly selected or case-converted, the ~[ or ~(
processing is terminated, and the outward search continues for a ~{ or
~< construct to be terminated. For example:
(setq tellstr "~#(~#[~R~]~^ ~A!~)")
=> "~#(~#[~R~]~^ ~A!~)"
(format nil tellstr 23) => "Twenty-three!"
(format nil tellstr nil "losers") => " Losers!"
(format nil tellstr 23 "losers") => "Twenty-three losers!"
I know there are a lot of questions out there with this headline, but I can't glean my answer from them, so here goes.
I'm an experienced programmer, but fairly new to Clojure. I'm trying to parse a RTF file by converting it to a HTML file then calling the html parser.
The converter I'm using (unrtf) always prints to stdout, so I need to capture the output and write the file myself.
(defn parse-rtf
"Use unrtf to parse a rtf file"
[#^java.io.InputStream istream charset]
(let [rtffile (File/createTempFile "parse" ".rtf" (File. "/vault/tmp/"))
htmlfile (File/createTempFile "parse" ".ohtml" (File. "/vault/tmp/"))
command (str "/usr/bin/unrtf "
(.getPath rtffile)
)
]
(try
(with-open [rtfout (FileOutputStream. rtffile)]
(IOUtils/copy istream rtfout))
(let [ proc (.exec (Runtime/getRuntime) command)
ostream (.getInputStream proc)
result (.waitFor proc)]
(if (> result 0)
(
(println "unrtf failed" command result)
; throwing an exception causes a parse failure to be logged
(throw (Exception. (str "RTF to HTML conversion failed")))
)
(
(with-open [htmlout (FileOutputStream. htmlfile)]
(IOUtils/copy ostream htmlout))
; since we now have html, run it through the html parser
(parse-html (FileInputStream. htmlfile) charset)
)
)
)
(finally
(.delete rtffile)
(.delete htmlfile)
)
)))
The exception points to the line with
(IOUtils/copy ostream htmlout))
which really confuses me, since I used that form earlier (just after the try:) and it seems to be OK there. I can't see the difference.
Thanks for any help you can give.
As others have correctly pointed out, you can't just add extra parentheses for code organization to group forms together. Parentheses in a Clojure file are tokens that delimit a list in the corresponding code; lists are evaluated as s-expressions - that is, the first form is evaluated and the result is invoked as a function (unless it names a special form such as if or let).
In this case you have the following:
(
(with-open [htmlout (FileOutputStream. htmlfile)]
(IOUtils/copy ostream htmlout))
; since we now have html, run it through the html parser
(parse-html (FileInputStream. htmlfile) charset)
)
The IOUtils/copy function has an integer return value (the number of bytes copied). This value is then returned when the surrounding with-open macro is evaluated. Since the with-open form is the first in a list, Clojure will then try to invoke the integer return value from IOUtils/copy as a function, resulting in the exception that you see.
To evaluate multiple forms for side-effects without invoking the result from the first one, wrap them in a do form; this is a special form that evaluates each expression and returns the result of the final expression, discarding the result from all others. Many core macros and special forms such as let, when, and with-open (among many others) accept multiple expressions and evaluate them in an implicit do.
I didnt try to run your code, just had a look at it, and after the if (> result 0) you have ((println ...)(throw ...)) without a do. Having an extra parens causes the returned value from the inner parens to be treated as a function and get executed.
try to include it, like this (do (println ...) (throw ...))