Fork me on GitHub
#clojure
<
2024-03-01
>
Ingy döt Net16:03:44

I need to generate blocks of clojure code where a save the evaluation value of each block into a mutable list. I've been at it for hours and learning a lot but haven't found a solution yet. Asking for help. Here's some simple examples that hopefully explain it: This is a minimal example of some code I might generate:

$ clojure -M -e '(eval (read-string "(def x 123)")) x'
#'user/x
123
I can wrap it in a do:
$ clojure -M -e '(do (eval (read-string "(def x 123)")) x)'
123
But I can't find any other fn, macro or special form that I can wrap that in:
$ clojure -M -e '(def ___ (do (eval (read-string "(def x 123)")) x))'
Syntax error compiling at (REPL:1:10).
Unable to resolve symbol: x in this context
I want to do something like:
$ clojure -M -e '(def ___ (atom []))  (swap! ___ conj (do (eval (read-string "(def x 123)")) x))  @___'
#'user/___
Syntax error compiling at (REPL:1:38).
Unable to resolve symbol: x in this context
Without the read-string/eval it works:
$ clojure -M -e '(def ___ (atom []))  (swap! ___ conj (do (def x 123) x))  @___'
#'user/___
[123]
[123]
I can see why, but hoping there's an easy solution. I was a bit surprised that def didn't work and do did, since they are both special forms. Maybe do is an "extra special" form :-] set! looked promising but I couldn't figure out how to make it work outside binding. Is this doable?

Alex Miller (Clojure team)16:03:52

do is extra special. But really I think you're importantly missing that -e evaluates exactly one expression and ignores whatever is after

Ingy döt Net16:03:00

$ clojure -M -e '1 2'
1
2

Alex Miller (Clojure team)16:03:01

seems like let would be useful here?

Ingy döt Net16:03:25

I tried let. I can try again...

Alex Miller (Clojure team)16:03:59

I stand corrected on -e, it does loop

Ingy döt Net16:03:08

$ wc `which clojure`
  491  1616 13498 /usr/local/bin/clojure

Alex Miller (Clojure team)16:03:11

I thought it only did one

Ingy döt Net16:03:45

I've seen 3 line versions of the clojure bash script

Ingy döt Net16:03:12

not sure how that one was install, but it's the big bash script

Ingy döt Net16:03:24

so they might behave different?

Alex Miller (Clojure team)16:03:26

ultimately they all call clojure.main, which should be the same

Ingy döt Net16:03:55

I'll try let again

Alex Miller (Clojure team)16:03:05

top level do is extra special in that it breaks up the exprs inside it and evals them each as top level expressions, and it's the only thing like that

Ingy döt Net16:03:47

$ clojure -M -e '(let [___ (do (eval (read-string "(def x 123)")) x)] ___)'
Syntax error compiling at (REPL:1:11).
Unable to resolve symbol: x in this context

Ingy döt Net16:03:34

I guess a do-set! thing is not possible.

Ingy döt Net16:03:34

I think I can do this another way. I just need to wrap the last form in the generated block, rather than the whole block.

Ingy döt Net16:03:02

Hoping that works out in all cases...

Alex Miller (Clojure team)16:03:29

I don’t understand what your actual goal is

Ingy döt Net17:03:03

It's too much to explain here. It took me a long time to work my problems into a form that I felt could be easily understood and talked about here. I got my definitive answer from you, and I really appreciate it. I'll stop pursuing that strategy and find another.

Ingy döt Net17:03:11

I'll write a quick summary of my goals in #C05HQFMTURF and link that thread back here.

Alex Miller (Clojure team)18:03:56

Seems like a top level do should be your friend

Ingy döt Net19:03:52

No. I need to capture the evaluation value of each group. And unless a group is at the top level (or inside a do) it will fail if it has symbols that need to be resolved at runtime. Wrapping it anything that can capture and save the value, cause it to not be at the top level. This works because the x symbol can be resolved at compile time (I'm no expert at exactly what "compile time" means so go easy on my words...):

$ clojure -M -e '(def ___ (atom []))  (swap! ___ conj (do (def x 123) x))  @___'
#'user/___
[123]
[123]
but when I replace the (def x 123) which something that evals it fails:
$ clojure -M -e '(def ___ (atom []))  (swap! ___ conj (do (eval (read-string "(def x 123)")) x))  @___'
#'user/___
Syntax error compiling at (REPL:1:38).
Unable to resolve symbol: x in this context
without trying to capture the result by wrapping it with something that can capture it also work:
$ clojure -M -e '(eval (read-string "(def x 123)")) x'
#'user/x
123
even with a do of course:
$ clojure -M -e '(do (eval (read-string "(def x 123)")) x)'
123

Ingy döt Net19:03:45

Fortunately my solution to wrap the last expr in a group seems to be working out perfectly:

$ clojure -M -e '(def ___ (atom []))  (do (eval (read-string "(def x 123)")) (swap! ___ conj x))  @___'
#'user/___
[123]
[123]

Ingy döt Net19:03:09

I already implemented it. Here's the input YS code, the result from running it and the compilation to Clojure code.

$ cat foo.ys 
- a
- b
---
- c
- d
--- !yamlscript/v0
a =: $$.1
b =: $$.2
concat: a b

$ ys -l foo.ys 
["a","b","c","d"]

$ ys -c foo.ys 
(+++ ["a" "b"])
(+++ ["c" "d"])
(def a (__ @$$ 1))
(def b (__ @$$ 2))
(+++ (concat a b))
I didn't need to create the a and b vars but I put them there to show how I wrap the last form in each compiled yaml doc with the +++ capture function.

Alex Miller (Clojure team)19:03:53

why are you trying to jam everything through -e ?

Alex Miller (Clojure team)19:03:09

you can pipe whatever you want through stdin

Ingy döt Net19:03:22

I just find it a convenient way to show short, easy to reproduce examples for these kind of discussions:

$ clojure -M -e '(do (eval (read-string "(def x 123)")) x)'
123
$ clojure -M <(echo '(do (eval (read-string "(def x 123)")) x)')
$ echo '(do (eval (read-string "(def x 123)")) x)' | clojure -M -
$ echo '(do (eval (read-string "(def x 123)")) (println x))' | clojure -M -
123
tomato, tomato, tomato But you made me realize that -e works out best because it prints the evaluation result for you. And it also is the shortest 🙂

Ingy döt Net19:03:06

I use -e one liners constantly for perl python ruby node bash clojure bb ys ...

3starblaze19:03:01

Hello! I'm building a library and I need an advice on how to best handle this situation. I need to generate Java classes that can: - subclass com.sun.jna.Structure - define multiple public fields - implement protected abstract List getFieldOrder() I looked at several options that Clojure has: reify, proxy and gen-class. It seems like gen-class might be the closest candidate but it looks like it is not possible to define multiple public fields there. In the worst case scenario I could print out Java files with classes that satisfy these conditions but I'm wondering if there is a better way. Thanks in advance! Context: In order to work with structs in JNA, I need to make Java classes that satisfy previously mentioned conditions. I did some investigating and it looks like there is no other option to define struct layout. Here are some links if additional info is needed: - http://java-native-access.github.io/jna/4.2.1/overview-summary.html#structures (About C struct JNA mapping) - https://github.com/java-native-access/jna/blob/master/www/Mappings.md (Java<->C data type mappings)

Alex Miller (Clojure team)19:03:09

there are no Clojure constructs designed to generate classes with those features

👍 1
phronmophobic19:03:14

Depending on how many classes you need to make, writing a bit of java for this purpose isn't too bad. Both https://github.com/phronmophobic/clong/ and dtype.next use https://github.com/jgpc42/insn to generate classes that work with JNA

phronmophobic19:03:16

In many cases, clong can automatically generate a clojure wrapper for a c library just by passing it some headers. If you're interested, there's a #clong channel. Otherwise, if you're going to roll your own, you can see what using insn might look like at https://github.com/phronmophobic/clong/blob/ff97f8ea88baf9974ee3ed518a3a34048f408690/src/com/phronemophobic/clong/gen/jna.clj#L202

3starblaze19:03:02

@U7RJTCH6J insn looks realy neat, it might be a good fit for me! I'll check it out later. Generating java source file probably won't be a big problem because it's rather obvious what needs to be written but if insn already satisfies my problems, I don't see a reason why I would need to make that Java source code generator. I'm not sure how helpful clong will be because the header I'm parsing is a bit odd. There's barely any functions defined in the header, instead I have typedefs and comments that explain API functions. I get a pointer that I can use to request a desired function and then I call that desired function. I pass header file to clang with -ast-dump=json and then analyze the dumped json.

👍 1
kwladyka23:03:31

Any suggestions which libraries I can use to check if in app there is icon on screen in some position of the screen? more detailed: 1) OS X - app can be run on another desktop (ctrl + arrow), so not exactly on the screen 2) windows - app on screen I want to check if in corner (rectangle) there is icon or not. Icon is known ahead, always the same.

p-himik11:03:20

A bit unclear what the actual problem is. Why do you need to check for the icon specifically and not, say, the window itself? If the icon represents some state, maybe it's possible to check for the state directly instead of "looking" at the icon?

kwladyka12:03:21

> maybe it’s possible to check for the state directly instead of it is not by intention

kwladyka12:03:35

don’t ask 🙂 just it needs to be done in this way

kwladyka13:03:24

> the window itself What do you mean?

lukasz23:03:43

it's been a while since I wrote anything for macOS desktop, but you won't be able to do this with Clojure, you're looking at ObjC/Swift and AppKit and window manager internals. Possibly also requesting screen recording permission & accessibility settings to be able to start figuring out if what you're looking for is on any screen. Listening to http://atp.fm podcast the complaining about window management APIs in macOS is a recurrent topic, aslo check the FAQ here https://hypercritical.co/switchglass/#faq

👍 1
p-himik23:03:01

On Windows, you can use https://www.autohotkey.com/. Despite its name, it's not really about hotkeys. The program and its scripting language are quite powerful. > What do you mean? You can trigger a function when a window with specific properties appears - the parent program, the title, window flags, I think even the window icon. And if what you want to do can only be achieved by searching for a specific image on screen, it can do that too.

👍 1
kwladyka23:03:54

ah this is what you mean, not it not a window icon, it is icon which app display in app area

kwladyka23:03:42

no way to make screenshot of the app from Java in OS X ? that would be not expected

p-himik23:03:26

You can make a screenshot in a platform-specific way, but searching for a specific image there will be much harder than with AutoHotkey and similar things.