clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
Helins 2021-02-18T12:00:13.235700Z

WAT, the Lisp format for WebAssembly, seems to be valid EDN (given it doesn't contain comments such as (; comment ;) ). I find it really exciting as it opens many possibilities. However, there is one caveat: numbers are parsed as numbers and this can be tricky. For instance, WASM can declare unsigned 64 bits constants which could be parsed as BigInts and mess things up. The EdnReader doesn't seem to be very hackable. What I would like is to gain control over how numbers are parsed, which is defined by this static method on the EdnReader: https://github.com/clojure/clojure/blob/ecd5ff59e07de649a9f9affb897d02165fe7e553/src/jvm/clojure/lang/EdnReader.java#L314 Any idea? Or another direction (besides writing another s-expr parser)?

borkdude 2021-02-18T12:06:41.236700Z

@adam678 https://github.com/borkdude/edamame has a postprocess hook in which you could possibly fix this. This is after the number has already been parsed but after that you can do whatever

borkdude 2021-02-18T12:08:15.237700Z

I'm not sure what the exact problem is. What is the data you expect and what is the data that currently comes out?

Helins 2021-02-18T12:12:08.239700Z

For instance, the parsed WAT cannot be reliably stringified without doing a second pass and transforming numbers to symbols (at least BigInts).

borkdude 2021-02-18T12:12:48.240Z

example?

Helins 2021-02-18T12:16:37.241300Z

(i64.const 18446744073709551615) -> (i64.const 18446744073709551615N) (`N` is appended) In that particular case, control over how BigInts are printed would be a simple solution (but haven't look at implementation)

borkdude 2021-02-18T12:19:51.242200Z

@adam678 Yeah, you could do it like this:

user=> (e/parse-string "(i64.const 18446744073709551615)" {:postprocess (fn [{:keys [:obj]}] (if (instance? clojure.lang.BigInt obj) (symbol (str obj)) obj))})
(i64.const 18446744073709551615)
or just use a postwalk over the EDN

borkdude 2021-02-18T12:20:16.242600Z

Note that symbols starting with a number aren't actually valid, so consider this a hack

Helins 2021-02-18T12:23:45.244800Z

Yep, too bad it requires a second pass just for this. Then I am a bit worried about subtle differences in floats since WASM is using a newer revision of IEEE754 (2019 vs 2008 in the JVM I believe). If there is any difference, then a second pass won't do, all numbers should be kept as symbols (albeit a hack).

borkdude 2021-02-18T12:24:15.245200Z

In edamame this is not a second pass, it transforms while parsing

borkdude 2021-02-18T12:24:46.245600Z

or if you mean, after you parse it to bigint, then yes

borkdude 2021-02-18T12:25:48.246400Z

Maybe you can look at the source of tools.reader.edn, edamame is mostly based on this. It's not actually that much work to write a decent parser for an alternative EDN

πŸ‘ 1
Helins 2021-02-18T12:33:40.246900Z

Hmmm, probably best to go that road for providing CLJS support anyways

Helins 2021-02-18T12:35:14.248300Z

But other than that, I find it remarkable. Being able to easily parse WASM as Clojure data structures. There is nothing better for handling a LISP than a LISP (and we have a good one).

2021-02-18T13:39:00.252800Z

Using this library https://github.com/cognitect-labs/aws-api for s3 service, everything is fine. Now need to add Amazon Gift Card Incentives API - which :api value should I provide on client creation? Tried dozen of words, such as :incentives, :AGCOD etc, but everytime got an error Cannot find resource cognitect/aws/AGCOD/service.edn . How can I find the right characters or where I can see the whole apis list? Or this library does not provide this api integration?

ghadi 2021-02-18T13:43:03.254100Z

I think that’s not an AWS service, but an http://Amazon.com Retail API

2021-02-18T13:44:12.255200Z

Hm, that means I can not use library above for integration with it?

ghadi 2021-02-18T13:44:21.255400Z

Correct

βœ… 1
2021-02-18T13:44:34.255700Z

Ok, thanks

Lyderic Dutillieux 2021-02-18T14:48:51.259700Z

Hey, I just stumbled on this argument in favor of dynamic scoping : https://stackoverflow.com/a/3792028 I was wondering if anyone knows a practical code sample that uses and takes profit of dynamic scoping ? I would like to see a concrete use case to soak up this concept

Ben Sless 2021-02-21T20:12:12.020100Z

This might as well be an argument in favor of openness and extensibility. Dynamic scope allows that, but it's indeterministic. You can solve the same problem by passing a context map instead of fixed arguments, use protocols and multimethods

πŸ‘ 1
borkdude 2021-02-18T14:54:17.260200Z

Are dynamic vars an alternative to this?

Lyderic Dutillieux 2021-02-18T14:58:57.260300Z

I guess they are a sort of workaround. In the case of EmacsLisp (where I discovered the concept of dynamic scoping), there is the concept of free variable, that are resolved in runtime, from several possible scopes (not especially global)

Lyderic Dutillieux 2021-02-18T15:06:15.260600Z

I looked a bit deeper, you are right, it does the job

Lyderic Dutillieux 2021-02-18T15:59:01.260900Z

Note : In Clojure, when I do

(defn get-x [] x)
I get a
Syntax error compiling at (REPL:1:15).
Unable to resolve symbol: x in this context
Whereas in EmacsLisp, I can define such a function when x is not declared yet :
(defun get-x () x)
And rebind x later, at runtime.
(let ((x 999)) (get-x)) => 999
In clojure, I can reach 'almost' the same behavior, given that I first (def ^:dynamic x 666) And then use something like binding
(def ^:dynamic x 666)
(defn get-x [] x)
(binding [x 999] (get-x)) => 999
x => 666

Ed 2021-02-18T16:36:05.261600Z

the errors you're getting that are different between elisp and clojure aren't to do with dynamic scope, but when the compiler/interpreter chooses to resolve the symbol. Clojure could equally have chosen to resolve the var x only when get-x in run without changing which x was resolved (you can do that by calling (resolve 'x))

πŸ˜ƒ 1
Ed 2021-02-18T16:40:35.262100Z

I've used dynamic scope to hide things from an API in the past, so the caller doesn't need to know about some implementation details ... I'm never very proud of myself when I've done this, but it's usually to get around some other limitation placed on what I'm trying to do by another bit of code (which I think what that RMS quote is getting at) ... and it usually restricts the utility of that code in ways that I wish it didn't ... but I think that I'm just not clever enough to solve the problem without dynamic scope, so I use it and accept the trade off πŸ˜‰

πŸ‘ 1
Ed 2021-02-18T16:43:11.264400Z

I thought dynamic vars were an implementation of dynamic scope ... and it looks different enough from lexical scope in Clojure, so you don't confuse the two, cos you usually want lexical scope

2021-02-18T16:43:40.265100Z

Is there an easy way to make failure messages part of clojure.test/are macro args? I have a large expr and many test values to run it over, and have to guess which test failed currently: I would like to avoid using a separate testing category and have to re-copy the are clauses over and over again. Thanks for any comment!

2021-02-18T16:45:37.266200Z

Ideally:

(deftest my-test
 (are [...] (....)
  vals-1 "whoa val 1 bad!"
 ...))

dpsutton 2021-02-18T16:54:34.266300Z

user=> (require '[clojure.test :refer :all])
nil
(deftest foo
  (are [x y] (is (= x y) (str x " was not equal to " y))
    1 1
    2 2
    3 4))
#'user/foo
user=> (foo)

FAIL in (foo) (NO_SOURCE_FILE:2)
3 was not equal to 4
expected: (= 3 4)
  actual: (not (= 3 4))

FAIL in (foo) (NO_SOURCE_FILE:2)
expected: (is (= 3 4) (str 3 " was not equal to " 4))
  actual: false
nil
user=>

dpsutton 2021-02-18T16:54:46.266500Z

you can use the good parts of is

2021-02-18T17:05:15.266700Z

Woaw cool! I didn’t think of that, thank you πŸ™‚

dpsutton 2021-02-18T17:06:05.266900Z

you'll see two test reports but small price to pay i guess

borkdude 2021-02-18T17:16:21.267100Z

I usually avoid are and use doseq instead. ;)

Sergiy Shevchuk 2021-02-18T17:50:07.273300Z

Hi all. Please correct me, if it’s not right channel for tech question. I’ll move it to other Have some trouble with core.match pattern. The goal is to detect arithmetic symbols in list, and construct final expression. E.G: β€˜(+ 1 1 (* 2 1) (- 1 1)) -> 3 Was trying to parse list with next func:

(defn custom-matcher [x]
  (if (seq x)
    (clojure.core.match/match [x]
                   [([+ & r] :seq)] :plus
                   [([- & r] :seq)] :minus
                   [([* & r] :seq)] :multiplication
                   [([/ & r] :seq)] :division
                   :else nil))
  )
But, it does not work properly. If I’ll call func with next argument: (custom-matcher ’(- 1 1)), works first case (:plus keyword), not :minus. Appreciate for advises.

2021-02-18T18:03:48.273700Z

you may need to quote symbols or something in match patterns

2021-02-18T18:04:09.274300Z

to match + and r are both the same kind of thing

2021-02-18T18:04:37.274800Z

and the way it treats symbols is as names to bind to parts of things

2021-02-18T18:05:21.275700Z

so you need some way to tell it that you intend it to check that the first thing is the literal symbol + and not just bind the first thing to the name +

2021-02-18T18:05:59.276200Z

so really it isn't working correctly for the plus case either

2021-02-18T18:06:48.277Z

I don't know enough core.match to know what you need to do to make it match literal symbols, but I would just try quoting

dpsutton 2021-02-18T18:09:19.277700Z

(match '(- 1 2)
  (('+ & r) :seq) :plus
  (('- & r) :seq) :minus
  :else :nope)
:minus

Sergiy Shevchuk 2021-02-18T18:09:31.277900Z

Yeeees, thanks! Quote helps!

dpsutton 2021-02-18T18:09:47.278300Z

the docstring mentions you can omit the vectors if you're matching on a single entity

Sergiy Shevchuk 2021-02-18T18:10:20.278800Z

Thanks to all! Now I can continue my tests!

2021-02-18T18:24:35.278900Z

Yes indeed, I could do without the extra report, but this is so much better than the alternative - was wondering whether writing a new/extended clojure.template for that would be much work..

2021-02-18T18:25:29.279100Z

@borkdude - thanks for the suggestion. How would you use the doseq to achieve the same efficiency as are?

2021-02-18T18:26:10.279300Z

..without the duplication? πŸ™‚

dpsutton 2021-02-18T18:30:42.279500Z

(doseq [[expected input] coll] (is (= execpted input (str input " didn't work")))

2021-02-18T18:35:21.279700Z

hmmm..interesting. I will try that inside are

dpsutton 2021-02-18T18:36:01.279900Z

instead of are

2021-02-18T18:36:07.280100Z

I think this is an alternative to are πŸ™‚ OK ths

2021-02-18T18:36:09.280300Z

thx

2021-02-18T18:44:34.280500Z

That works well, thank you! A bit more to set up, with putting all the code at the end and partitioning but nice πŸ™‚

borkdude 2021-02-18T18:44:48.280700Z

Yeah, like:

(deftest foo
  (doseq [[x y] [[1 1]
                 [2 2]
                 [3 4]]]
    (is (= x y) (str x " was not equal to " y))))
Obviously this is more verbose than are but for the life of me, I can't remember the are syntax

βž• 1
2021-02-18T18:46:16.280900Z

Actually it is the same as doseq, except for the code/data order and are doing the partitioning for you - it would be nice to have a new version of are that does the same. Thanks!

borkdude 2021-02-18T18:48:02.281100Z

The partitioning is confusing imo. The grouping in a vector indicates... grouping :)

2021-02-18T18:48:50.282100Z

Indeed πŸ™‚ I agree, but I got used to the \n partitioning and not worrying about extra brackets, a matter of comfort I guess

vemv 2021-02-18T19:43:37.282500Z

My way to avoid are's double failure report is wrap in testing and add a true at test position. This pattern is captured in an IDE snippet https://raw.githubusercontent.com/zenmacs/.emacs.d/62d24aac7b2e57b3d31123d5de1c5980651054d5/snippets/clojure-mode/are so I don't have to remember various intricacies

borkdude 2021-02-18T19:45:02.282700Z

Another argument to never look at are again ;)

dpsutton 2021-02-18T19:45:22.282900Z

ha

vemv 2021-02-18T19:45:55.283100Z

Personally I'm a heavy arer and have convinced multiple teams of its benefits. There's also place for doseq, and occasionally use it. One day I'll like to summarize my thinking in an article

Lyderic Dutillieux 2021-02-18T21:52:24.284200Z

I didn't know about (resolve 'random-symbol) I just tested, and it actually works as well, thanks for the tips. Cool feedback about your experience with this, tx πŸ˜‰