Fork me on GitHub
#beginners
<
2018-06-23
>
non.dmitriy11:06:01

Hi guys! I'm writing little clojure scripts. And I tried to use clojure.tools but it should be installed. So I wonder if I can do something like in ruby: gem install clojure.tools to get latest version and just continue scripting.

manas.marthi11:06:19

You can use leiningen build tool. Install lein. Run lein new app

manas.marthi11:06:44

You have to add all dependencies to project.clj

non.dmitriy11:06:07

I know about lein. I am writing scripts. I dont need a whole project, I just need a single library

manas.marthi11:06:11

Will download jars

non.dmitriy11:06:44

running them using clj

manas.marthi11:06:16

In yourscript do you have ns macro?

non.dmitriy11:06:03

no.

#!/usr/bin/env clojure
(println "whatever")

manas.marthi11:06:05

(ns mynamespace.scripts (:require [clojure.tools :as tools])

manas.marthi11:06:46

That will import clojure.tools into your code

non.dmitriy11:06:12

I do use (require 'clojure.tools) but compiler can't locate them

manas.marthi11:06:14

You can use (tools/a-fn )

non.dmitriy11:06:24

You dont hear me. I know about lein and I know how to require library. The question is can I install it with one command to have it in classpath via using clj

non.dmitriy11:06:19

just like with gem install or npm install --global

manas.marthi11:06:13

You can download the jar to project folder, add it to classpath before starting clojure, or add the jar in the Java -cp myjars:clojure.jar clojure.main myscripy.clj

orestis11:06:11

@non.dmitriy The clj tool will find dependencies on your deps.edn file and download them on first invocation. It doesn’t require a separate step like gem/pip/npm do.

orestis11:06:46

If you are writing scripts, you can even pass the deps.edn as a command line argument and it will be the same.

non.dmitriy11:06:06

@orestis yeah, i've read this. But I REALLY dont wanna have more than one file per script.

non.dmitriy11:06:59

so this is not even near to what I asked about. It's not really much different from having a lein project

orestis11:06:04

Your objective is to not even have a deps.edn file, right? Just a single .clj file?

orestis11:06:04

I’m also a beginner but as far as I know, there are a couple of ways to accomplish them — unfortunately I’m on mobile so can’t dig around too much.

orestis11:06:53

First one is to invoke clj passing in the dependencies as command line arguments. Essentially typing out your deps.edn on command invocation.

orestis11:06:18

Second is to use a “global” deps.edn with common dependencies.

orestis11:06:47

And I think there might be a way to have a hash bang #!/usr/bin/clj that even includes deps as command line args.

non.dmitriy11:06:00

well, your first point covers last:) I will look into it, thanks

orestis11:06:30

Might be good to ask in #tools-deps too!

orestis11:06:54

Would be nice to have self contained clj files, I agree.

kwcharllie37912:06:15

Hello I'm trying to resolve the and symbol but it returns true instead of false here. How can I make it work?`((resolve (symbol "and")) true false)`

non.dmitriy12:06:25

@kwcharllie379 and is a macro so I guess you need to dig in this direction

kwcharllie37912:06:04

ahh I forgotten about that

kwcharllie37912:06:38

So I should do macroexpand 😛

non.dmitriy12:06:04

@orestis well, turns out shebang requires to use only one option without whitespaces so I cant pass deps hash to clj. I can create some wrapping script but it kinda smelly:(((

kwcharllie37912:06:06

Macroexpand does not work as well. Do not know how to do it then.

non.dmitriy12:06:01

@kwcharllie379 why can't you just use ((symbol "and") true false) ?

non.dmitriy12:06:02

forget it, I am stupid:)

bronsa12:06:51

@karolinasokolowska you can't apply a macro as a function

bronsa12:06:03

err @kwcharllie379

bronsa12:06:24

a macro is a function from data -> data that takes 2 extra parameters &env and &meta

kwcharllie37912:06:33

So literally there is no possibility to somehow call it?

non.dmitriy12:06:36

@kwcharllie379 try (eval (macroexpand (list (symbol "and") true false)))

bronsa12:06:38

so ((resolve 'and) true false) is passing true as &form and false as &env, and no arguments

bronsa12:06:45

it's equivalent to doing (and)

bronsa12:06:52

look what happens if you pass it more than 2 arguments

bronsa12:06:11

user=> ((resolve 'and) nil nil true false true)
(clojure.core/let [and__5324__auto__ true] (if and__5324__auto__ (clojure.core/and false true) and__5324__auto__))

bronsa12:06:38

what are you actually trying to do?

non.dmitriy12:06:03

My solution should work. You just expand macro and eval it.

kwcharllie37912:06:16

Yes it's working

non.dmitriy12:06:18

macroexpand accepts list. It is not macro itself

bronsa12:06:12

the above is equivalent to just

(eval (macroexpand `(and true false))

bronsa12:06:24

but what is it that you're trying to do?

kwcharllie37912:06:44

ok here is my fn

(defn- logic-op [a-str b-str op]
  (let [a-vec (s/split a-str #"")
        b-vec (s/split b-str #"")]
    (s/join
     (map #(if (eval (macroexpand (list (symbol op) (= %1 "1") (= %2 "1"))))
             1 0)
          a-vec b-vec))))

non.dmitriy12:06:02

or without list: (eval (macroexpand (~(symbol "and") true true)))`

bronsa12:06:03

there's better ways to do that

non.dmitriy12:06:06

(eval (macroexpand `(~(symbol "and") true true)))

bronsa12:06:20

use a map from symbol to function

non.dmitriy12:06:19

@bronsa not sure if I got it. You suggest preparing a hashmap with functions including and ?

bronsa12:06:36

({'and (fn [x y] (and x y))} (symbol op) (= %1 "1") (= %2 "2"))

bronsa12:06:50

invoking eval like that is not a good idea

non.dmitriy12:06:59

what if you will have MAAAANY functions?

non.dmitriy12:06:22

on what is your input

non.dmitriy12:06:40

getting one from the internet is a bad idea, yeah:D

non.dmitriy12:06:12

anyway, this is out of context. We answered initial question

bronsa12:06:31

you don't need the macroexpand there anyway

bronsa12:06:35

eval will macroexpand

non.dmitriy12:06:44

oh yeah? that's nice:)

kwcharllie37912:06:34

eval macroexapnds?

kwcharllie37912:06:45

Guys you're great

kwcharllie37912:06:34

My inputs are strings like "111" "1111001" and so on

bronsa12:06:15

REPL is (loop (print (eval (read))), eval is (emit (analyze (macroexpand form)))

kwcharllie37912:06:02

I have to put that information somewhere in my notes. Thank you @bronsa

kwcharllie37912:06:23

thank you @non.dmitriy

non.dmitriy12:06:58

I am still looking for solution to run a script with dependent library via single file with shebang.

bronsa12:06:15

#!/bin/sh

true;exec clojure -Sdeps '{:deps {my-deps-here}}' -i "$0"
true;exit

(require 'my-deps)
(println "hello")

lady3janepl14:06:36

Hey, looking for ideas on how to simplify a function

lady3janepl14:06:46

The input is a list of elements. The loop-body is to split the list into 2-element pairs and merge each pair (which I do via partition-by and map appropriate-merge-fn) The loop-end-condition is to stop when the list has only 1 element How would you execute the looping part? The clearest mechanism for me right now would be loop-recur, but I remember reading that people should try to use other functions. There’s iterate+drop-while, but that feels… clunky. (Note: I know I could use reduce; bear with me, this is an exercise.)

non.dmitriy14:06:51

yeah, I though about that. Kinda smelly though:D

lady3janepl15:06:10

Also, style question. For argument validation, would you throw IllegalArgumentException or use {:pre []} assertion?

bronsa15:06:10

@lady3janepl you can reduce over the list of pairs and terminate the reduction using reduced

bronsa15:06:55

if I understood correctly

lady3janepl15:06:27

@bronsa that’s brilliant, I needed that functionality for something else 😄 but not sure it would do what I want here, let me type out an example

lady3janepl15:06:16

Let’s say list elements are integers, and the merge function is +. Then:

input: [ 1 2 3 4 5 ]
(enter loop)
after first pass: [ 3 7 5 ]
after second pass: [ 10 5 ]
after third pass: [ 15 ]
(loop terminates)
return: 15
The list with merged elements from the first pass gets chunked again in second pass.

lady3janepl15:06:52

my current code is, with type-specific adaptations removed:

(loop [xs xs]
     (if (= 1 (count xs))
       (first xs)
       (recur (map #(merge2 (first %) (second %)) (partition-all 2 xs)))))

lady3janepl15:06:10

feels a bit silly though

bronsa16:06:11

I'd use iterate + drop-while for that then

lady3janepl16:06:35

:+1: thanks 🙂