"Ran into a RPAREN where it wasn't expected" when using "->>" - hy

I have the following code:
(require [hyrule [-> ->>]])
(defn static/freezer [value freezer]
(cond [(not value) (setv freezer [])]
[(isinstance value list)
(do (if (not (isinstance freezer list)) (setv freezer []))
(.extend freezer value)
(setv freezer (->> (lfor i
(lfor j freezer :if j j)
(if (isinstance i list) i [i]))
(list)
(chain #*))))]
[True (raise (TypeError f"Sorry! The 'm/freezer' can only accept lists or non-truthy values!"))])
(return freezer))
(print (static/freezer [[1 2] [3 4] 5))
... but am getting the following error:
Traceback (most recent call last):
File "/usr/lib/python3.9/runpy.py", line 267, in run_path
code, fname = _get_code_from_file(run_name, path_name)
File "/home/shadowrylander/bakery/test.hy", line 12
(chain #*))))]
^
hy.lex.exceptions.LexException: Ran into a RPAREN where it wasn't expected.
I am assuming the ->> macro isn't taking effect, as every bracket checks out, but neither eval-when-compile nor eval-after-compile helps.

As suggested by the error message, (chain #*) is not lexically legal. #*, as well as #**, must be followed by a form. The underlying idea is that #* and #**, like ( and ", are not forms themselves, but characters that can be used along with some other characters to construct forms, namely (unpack-iterable …) and (unpack-mapping …). #1730 discusses some related issues. At any rate, lexing happens before any macros are expanded, so ->> can't get around this.

Related

Locally rebinding `+`

How to translate this Clojure code to Hy, so it prints 2?
It doesn't need to be like Clojure, i just want to hide + and replace it with - in local environment.
(defmacro q [expr]
`(let ~'[+ (fn [x y] (- x y))]
~expr))
(print (q (+ 3 1)))
In Clojure it prints 2 (let creates a local environment).
In Hy it prints 4.
How to make Hy print 2 also, by replacing the + with - ?
I need those local environments because i am making a DSL.
This doesn't do what you expect in Hy because + is a macro, and macro calls take precedence over function calls:
(defmacro x [] 1)
(defn x [] 2)
(print (x)) ; => 1
Your options are:
Instead of +, use a name doesn't have the same name as a core macro, like my+ or +2.
Only use your new + in contexts other than the head of an Expression (which is the only place Hy expands macro calls), such as (map + (range 10)).
In q, replace the symbol + in the input instead of just setting the variable +, as in something like
(defmacro q [expr]
(import hyrule [coll?])
(defn f [x]
(cond
(= x '+) '-
(coll? x) ((type x) (map f x))
True x))
(f expr))
(print (q (+ 3 1)))
Use defmacro to define a new macro named +. This is a bad idea because you lose access to the original + in this module, including in the expansions of macros you didn't write that expect + to have its usual meaning. Local macros are not yet implemented (#900).

Last element of an Array in Clojure

Is there any simplier way to find the last element of an array in clojure except this function?
(fn [l] (if (empty? (rest l)) (first l) (recur (rest l))))
For vectors, use peek for constant time
user=> (peek [1 2 3 4 5])
5
For Java arrays,
user=> (let [a (to-array [1 2 3 4 5])] (aget a (dec (alength a))))
5
For a general collection, you can get the last item in linear time with last. It is defined similarly to what you have done.
user=> (source last)
(def
^{:arglists '([coll])
:doc "Return the last item in coll, in linear time"
:added "1.0"
:static true}
last (fn ^:static last [s]
(if (next s)
(recur (next s))
(first s))))
The simplest way is to use (last l) that works in linear time (http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/last)
Another possibility is to reverse your collection and take the first element: ((comp first reverse) l). But that's rather slow as reverse returns a non-lazy sequence. Note: comp returns a composition of its arguments (functions) (http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/comp)
You can also convert the collection to a vector first and then apply peek: ((comp peek vec) l). This should have a better performance.
Another one: determine the length of your collection and take the last element (#(nth % (dec (count %))) l).
These functions work for all collection types (e.g. vectors, lists, ...). There are no arrays per se in Clojure (except you want to use Java arrays).

How to store a broken-Scheme-string in an array or a vector?

I get as an input a string , and I want to store it in an array or
a vector , so I would be able to check the values of the broken string .
Here I break the string into chars :
(define (dealBreaker str) (string->list str)) ; break the string into chars
But when I try to declare a simple vector :
(define (myVector (make-vector 4 (/ 1 2))))
I get this : #%plain-lambda: not an identifier in: (make-vector 4 (/ 1 2))
How can I declare a vector called someVector for the broken characters from dealBreaker method above ?
Try this, for some str string:
(define (dealBreaker str)
(list->vector (string->list str)))
(define myVector (dealBreaker "some string"))
myVector
=> '#(#\s #\o #\m #\e #\space #\s #\t #\r #\i #\n #\g)
The above will create a new vector from the characters in the string, is that what you need?
The problem here is that define should be
(define identifier value)
but right now you have
(define (identifier value))
So try
(define myVector (make-vector 4 (/ 1 2)))
It's a little confusing, because in Scheme, define is overloaded, there's also
(define (functionName formals) body)
but that's purely syntactical sugar for
(define functionName
(lambda formals body))
Side note: Several beginner scheme textbooks recommend using the lambda version since it's more explicit.
In this case though, just do:
(define myVec (list->vector (dealBreaker str)))
The immediate problem you're having with myVector appears to be due to a misplaced paren - try this instead and see if it resolves the 'plain-lambda' error:
(define myVector (make-vector 4 (/ 1 2)))
On the question of converting the 'dealBreaker' string to a vector, you should be able to do this:
(define (someVector dealBreakerList) (list->vector dealBreakerList))
(someVector (dealBreaker "someString"))
Or if you want 'someVector' as the complete function:
(define (someVector str) (list->vector (string->list str)))
(someVector "someString")

Parsing of nested array structure

I'm trying to parse a nested array structure of the following form:
[element [[child1] [child2] [child3 [[subchild1] [subchild2]]]]]
I would also like to return a list with all symbols (and nothing else), regardless of nesting depth; however, I'm not looking for flatmap or flatten etc, since I need to perform more complicated additional work on every element.
This is what I came up with so far:
(defn create-element [rs element]
(if (symbol? element)
(cons element rs)
rs))
(defn parse
([rs element] (create-element rs element))
([rs element [children & more]] (if (nil? more)
(parse (parse rs element) (first children))
(parse (parse rs element) (first children) more))))
(defn n-parse [element]
(apply parse () element))
This works fine for the following input:
=> (n-parse ['bla [['asd] ['kkk] ['sss]]])
(sss kkk asd bla)
But this doesn't work:
=> (n-parse ['bla [['asd] ['kkk [['ooo]]] ['sss]]])
(sss kkk asd bla)
I'm still trying to wrap around my head around the types but can't seem to manage to get it right. For example, Haskell makes this easy with pattern matching etc, whereas Clojure doesn't allow same arity function overloading.
Also is there a more concise / idiomatic way (without having to resort to if?) I'd prefer pure Clojure solutions (no external libs) since this is actually for a Clojurescipt project.
Many thanks for any help!
I don't see whats wrong with flatten. If you want to do some work on the items first, do the work first and then flatten the result:
(defn map-tree
"Example: (map-tree + [1 2 [3 5]] [3 4 [5 6]])"
[f & trees]
(if (every? coll? trees)
(apply map (partial map-tree f) trees)
(apply f trees)))
(defmulti transformator identity)
;; transform 'sss element into something special
(defmethod transformator 'sss [_] "sss")
;; default transformation
(defmethod transformator :default [v] v)
Test:
user> (flatten (map-tree transformator '[bla [[asd] [kkk] [sss]]]))
(bla asd kkk "sss")
user>
Would that not work?

How do I print a list of numbers on each line in clojure?

how can I print a list of n, say 10, numbers on 10 lines? I just learned about loop and recur, but cannot seem to combine a side-effect (println i) with (recur (+ i 1)) in a loop form.
Just to be very clear: I'd like output like this:
1
2
3
4
5
6
7
8
9
10
when n is 10.
You can use doseq for this, which is meant to be used when iteration involves side effects,
(doseq [i (range 10)]
(println i))
You could use map as pointed but that will produce a sequence full of nils which is both not idiomatic and wastes resources also doseq is not lazy so no need to force it with doall.
I suggest dotimes for this kind of simple loop:
(dotimes [i 10]
(println (inc i)))
Note that dotimes is non-lazy, so it is good for things like println that cause side effects.
With loop/recur:
(loop [i 1]
(when (<= i 10)
(println i)
(recur (inc i))))
However, it's more idiomatic (read: more "Clojuristic") to map the function println over the numbers in 1..10. But because map returns a lazy sequence, you must force its evaluation with doall:
(doall (map println (range 1 (inc 10))))
And just to be comprehensive you can do it with map also:
(doseq (map #(println %) (range 10))
If you only want to print the output on the screen, you might also simply put a (println i) before entering your conditional:
(loop [i 0]
(println i)
(if (< i 10)
(recur (inc i))
(println "done!")))
And the output will be one number per line.

Resources