Fork me on GitHub
#beginners
<
2018-08-13
>
new clojure student01:08:48

I have no idea what that error means. What I'm doing seems straightforward.

new clojure student01:08:31

The issue seems to be that args is an ArraySeq ? How do I unpack it into a number? Is there a more elegant way to test one-less-arg?

noisesmith01:08:44

if you change (f x args) to (apply f x args) it should do what you want

noisesmith01:08:14

apply takes a function, and a arglist (and N optional args before the arglist)

mikeyford09:08:26

Hey all, is there a good way to set CIDER to pprint by default? in the process of expriementing with switching over from cursive, and it's something I miss

Karol Wójcik14:08:00

@michael.ford I just found cider-toggle-repl-pretty-print- method 🙂 You must check it out 🙂

Karol Wójcik10:08:06

Well. I don't think that it's a good idea. print is for printing pprint is for pretty printing

Karol Wójcik10:08:32

You can always use pprint to print sth to the repl

jgh10:08:44

do you guys have a recommended lib for parsing binary data?

jgh10:08:39

buffy looks pretty good

jgh10:08:22

octet looks ok but maybe less flexible than buffy

dimitrijer11:08:33

Have you tried gloss? I used it once and it was very nice

jgh11:08:50

i have not, but it looks like it's no longer in development

dimitrijer11:08:37

Yeah, I used it a couple of years ago, was active back then.

schmee11:08:40

gloss + aleph is really nice for TCP binary protocols

joshkh11:08:08

any idea what i'm doing wrong here?

; This works
(s/describe :myspec/a-thing)
=> (keys ...)

(s/gen :myspec/a-thing)
FileNotFoundException Could not locate clojure/test/check/generators__init.class or clojure/test/check/generators.clj on classpath.  clojure.lang.RT.load (RT.java:463)

schmee11:08:08

@joshkh have you imported clojure.spec.gen.alpha?

schmee11:08:32

oh, you might also need to add test.check as a dependency

joshkh11:08:04

yup, definitely imported. i'll try test.check.

schmee11:08:27

[org.clojure/test.check "0.10.0-alpha3"]

👍 4
joshkh11:08:23

that did the trick, thanks @schmee

joshkh11:08:00

recently i've had plenty of missing dependency issues. datomic, spec etc. could that be a java10 thing?

schmee11:08:07

nah, for whatever reason these projects have “optional” dependencies that you only need if you use certain parts

schmee11:08:29

but as you just noticed this becomes confusing if you’re not aware that this is the case, and what these parts are

joshkh11:08:53

:man-shrugging:

dpsutton12:08:16

@michael.ford in the repl press comma and you will see a very useful list of helpers. One of which is to toggle pretty printing

4
mikeyford12:08:02

Amazing! Thank you.

cristibalan13:08:28

I'm trying to find the first key in a list that exists on a map. With all keywords, I can use (some m (sorted-set :a :b)). Is there a way to do this when one of the searched keys is a string?

cristibalan13:08:18

Actually, right after typing, I realised the order of the keys doesn't matter so I'll just use #{:a "b"}. Would be nice to know if there's a way tho 🙂

mfikes13:08:26

@cristibalan Compare (some {:a 1 :b 2} [:a :b]) and (some {:a 1 :b 2} [:b :a])

mfikes13:08:48

The key aspect is that order of the elements in the collection is important. Also, you have to decide if false-y is important to find

(some {:a 1 :b 2 :c false} [:c :b :a])

Alex Miller (Clojure team)13:08:02

if they are keywords or strings, you could sort-by name

Alex Miller (Clojure team)13:08:35

name happens to work on both identifiers and strings and turn them all into strings

reborg13:08:24

What about (first (select-keys m l)) @cristibalan?

reborg13:08:12

scratch that, that doesn't work for large "l"

reborg13:08:55

this (some (set (keys m)) l) should work (if I understand the question)

👍 4
cristibalan13:08:22

@reborg It seems that still returns whatever the collection happens to have sorted first. I am trying to find out the first of the keys in the list (in the order given by the list) that exists in the map, when the keys can be either keywords or strings.

reborg14:08:37

Can you post a counter example? I have the following (I don't think it changes int-str-keyword keys):

(def m (zipmap (range 20) (range 20)))
(def l [:a 5 "1" 6 1])
(some (set (keys m)) l)
;; 5

cristibalan14:08:59

I'm expecting :b to be returned here:

(def x {:b 2 :a 1 :c 3 "d" 4})
(some (set (keys x)) #{:b "d"})

cristibalan14:08:38

Oh wait, misread your example.

cristibalan14:08:50

Success!

(some (set (keys x)) [:b "d"]) ;; => :b

reborg14:08:41

Yes, unless you need the second arg to be a set

cristibalan14:08:15

I see, thanks. I was using a set there probably because I was confusing the location of the pred argument to some.

cristibalan14:08:38

@alexmiller That's a good alternative to #{"b" :a}, but changes the order of the searched keys.

cristibalan14:08:49

@mfikes Thanks. Yeah, I'm definitely not trying to count on the order of the elements in the map.

mfikes14:08:13

Right, the order of the elements in the map is not important. The ordered collection is the second argument @cristibalan

mfikes14:08:19

In other words counting on (seq #{:a "b"}) being (:a "b") is the thing to watch out for

beders17:08:21

is there a way to avoid having to re-launch the REPL just because I'm adding a dependency?

beders17:08:45

is there some magic switch that'll turn on a better URLClassLoader for deps?

dadair17:08:08

@beders clj-refactor (an emacs package) allows you to add a project dependency and hot-reload the dep into the REPL https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-add-project-dependency

dadair17:08:30

assuming leiningen/boot and emacs, of course

beders17:08:47

unfortunately I'm on IntelliJ-Cursive. I wish this would be standard part of the repl that leiningen starts

beders17:08:58

thanks for the pointer, I'll have a look

beders17:08:12

losing my playground because I need one more dependency makes me sad 😞

dadair17:08:32

You could ask in #cursive, I’m not sure if there’s something built-in

noisesmith17:08:07

> unfortunately I'm on IntelliJ-Cursive if you are using leiningen the plugin will work (but cursive may or may not understand the new deps correctly)

placeboza17:08:40

The trouble I have with becoming skilled with Clojure is that I'm already very familiar with C#. When trying to create a non-trivial system with Clojure, I'm always dragged back into minutia that I take for granted in Visual Studio & C#. And debugging in Clojure vs VS seems night and day 😕

placeboza17:08:54

Is Emacs + Cider worth learning because it has a better debugger available?

placeboza17:08:17

(Using LightTable so far, where live coding is awesome but debugging not so much)

jonahbenton17:08:56

Did you try Cursive (based on Intellij)?

placeboza17:08:30

@jonahbenton No, I've so far been very windows/CLR focussed - part of my difficulty I guess (learning JVM) - is it better than the Emacs/Cider combo? I've briefly used Emacs before, and was starting to get the hang of it

Komcrad17:08:43

@placeboza I come from a java background. I use vim and a basic repl started with leiningen. Using the repl and mostly functional code, I've never felt I needed a debugger like you'd find in java + eclipse.

👍 4
placeboza17:08:47

Just a different workflow from what I'm used to I suppose

noisesmith17:08:06

yeah, the fact that the majority of values in-situ in your running system are immutable means that simply storing the values that come in at runtime then playing with them in the repl can do most of your debugging needs

noisesmith17:08:48

and you hardly need tooling with that, either def or an atom and swap! or reset! should get you going

noisesmith17:08:37

the language has so much built in for introspecting and operating on structured data that I tend to just do this for a majority of cases

Komcrad17:08:40

It is a very different workflow. But I'd argue having the repl in your workflow is a huge advantage that clojure has. I'm far more confident in what I write when I'm using the repl during development because I immediately know what works and what doesn't.

placeboza18:08:19

Right, so I guess the power of the language covers for the limited tooling to some extent. But it does require some innovative thinking, which is making it difficult for me to focus on the overall solution I'm trying to make. Like that old saying - "It's hard to think of draining the swamp when you're chased by the crocodiles"

placeboza18:08:06

Thanks, just wanted some insight into how others are using it - seems that I need to just get more familiar with the language features then

noisesmith18:08:16

yeah, and learning a new editor at the same time often makes that worse

placeboza18:08:37

Yup. I have so much muscle memory in using e.g. Visual Studio with Resharper

placeboza18:08:04

But the power and grace in Clojure attracts me so much

noisesmith18:08:05

there is a vs-code plugin for clojure, I've heard it actually works well

placeboza18:08:26

I've actually done some coding with ClojureCLR and it wasn't bad, but it was a bit slow

noisesmith18:08:32

also, clj-clr exists, you can use it with the standard clr tooling (eg. nuget) - it just lacks dedicated tooling

noisesmith18:08:40

it's up to date with clj-java usually

placeboza18:08:42

Yeah, it's not as well supported

noisesmith18:08:04

the language side is well supported and working afaik, it just lacks 3rd party tools

noisesmith18:08:20

(this might no longer be true)

placeboza18:08:37

I believe the features work well, but the CLR causes some performance issues - it wasn't quite designed for an immutable FP with some innovative ideas

placeboza18:08:43

Last time I checked

Komcrad18:08:47

As far as a more traditional debugger. I'd look into the cursive plugin for intelij as @jonahbenton suggested. No reason you can't have the best of both worlds. I'd still highly recommend trying out a workflow focused around the repl.

👍 4
placeboza18:08:00

The way I see it - you can build a relatively bug-free piece of code very well in a repl. But my concern is when you hit an nasty, intermittent bug that isn't obvious - a call stack at least comes in handy then

placeboza18:08:42

i.e. the repl is a great way to build the code but doesn't seem like a great way to remove bugs from a sizeable existing bit of code

placeboza18:08:51

Could be wrong of course

noisesmith18:08:50

the call-stack visibility works out in a vanilla repl, but often gets obfuscated by tooling that is too clever for its own good

placeboza18:08:34

It being dynamically typed does make it trickier for tool makers, I imagine.

placeboza18:08:11

And macros, lambdas

noisesmith18:08:58

a lambda is just an instance of an anonymous class implementing IFn

noisesmith18:08:18

(I mean, that might be rare in your java / c# coding style, but isn't totally alien)

noisesmith18:08:47

laziness doesn't play nicely with stack trace reading though - easily counterintuitive

placeboza18:08:52

Yeah, I just mean for debugging it can complicate things wrt deferring the execution. (Esp if it's anon)

noisesmith18:08:46

fun trick - you can make an anon-fn with a name

(ins)user=> (fn [])
#object[user$eval158$fn__159 0x61e94def "user$eval158$fn__159@61e94def"]
(ins)user=> (fn foo [])
#object[user$eval162$foo__163 0x5b068087 "user$eval162$foo__163@5b068087"]

👍 8
placeboza18:08:48

Did know that, but good tip for beginners room

placeboza18:08:09

defn is essentially (def xx (fn [] ...))

noisesmith18:08:51

right, but I think it does use that optional name arg to fn

noisesmith18:08:07

so (def xx (fn xx [] ...)) edit: it doesn't do that, but there's a comment saying it should and why it doesn't

noisesmith18:08:23

I pretty much only use that feature for making stack traces easier to read (though it's also useful for non-tail recursion)

👍 4
placeboza18:08:09

boot vs lein - preferences?

noisesmith18:08:51

for a beginner using lein is simpler - most documentation for non core libs and tooling assumes lein

noisesmith18:08:32

boot can be useful for more complex builds that work against lein's assumptions / defaults, but is easier to pick up if you know lein first

👍 4
placeboza18:08:04

I have some basic familiarity with lein, sounds like I will investigate boot when I need more power

noisesmith18:08:13

in my experience most boot users end up there because they wanted a more optimized build, or their project.clj config in lein was getting overly complex boot lets you run arbitrary code, it's not a declarative data structure file but a script to run

hiredman18:08:24

I think most people have a terrible build process, and boot isn't as opinionated as lein is, so it is happy to let you wallow in your terrible build, where as you will have to fight with lein to get it to do the terrible things you want done

hiredman18:08:55

to characterize boot as more powerful in some way is just factually wrong, but you won't have to fight it to introduce a build dependency on the phase of the moon as much

👍 4
placeboza18:08:52

lein = more directed/opinionated then

placeboza18:08:10

which is better to begin with

placeboza18:08:40

i.e. perhaps a newbie like me might tie himself in knots with boot?

placeboza18:08:10

Another opinion question => mount or component? 🙂 (for lifecycle/state management)

mg18:08:58

I prefer component, some prefer mount

hiredman19:08:02

I will never understand why anyone thinks mount is a good idea

jonahbenton19:08:44

another +1 for component

noisesmith19:08:21

mount relies on singleton global mutable state, component explicitly avoids that

manas_marthi19:08:06

Hi I am unable to loop through the chars of a string (-> "ABCDEF" (seq) (Character/toString) (Character/codePointAt 0) (println))

manas_marthi19:08:12

It's nt working

manas_marthi19:08:44

please advise how to stream chars of a string into the threading

placeboza19:08:13

mount looked slightly prettier, but agree with the global state comment

noisesmith19:08:31

Character/toString takes a character, you are passing it (seq "ABCDEF") which is a list of characters

noisesmith19:08:06

-> isn't a streaming operator, it's a macro that manipulates your code before compiling it

noisesmith19:08:08

user=> (macroexpand '(-> foo bar (baz OK) quux))
(quux (baz (bar foo) OK))

4
noisesmith19:08:20

@manas.marthi perhaps what you want is (->> "ABCDEF" (seq) (map #(Character/toString %)) ...) - note that this requires using ->> (thread last) instead of -> (thread first)

placeboza19:08:24

Missing a map then <- edit: snap

noisesmith19:08:36

or some other iteration construct, yes

noisesmith19:08:03

also map implicitly calls seq, I left it for simplicity's sake

placeboza19:08:04

Let the war begin 😄

Patrick Hildreth19:08:27

(map #(Character/toString %) (seq "ABC"))

noisesmith19:08:05

idiomatically, just (map str "ABC")

✔️ 12
placeboza19:08:43

@pauld Doesn't the global nature of the defstates hold you back? i.e. don't think it lets you have local contexts like you would typically with other DI approaches

manas_marthi19:08:04

I have a large text. I want to find the frequencies of chars.. I used (frequencies (slurp (io/resource "myfile.txt"))) to get the map

manas_marthi19:08:13

how do I sort this on values?

noisesmith19:08:25

(sort-by val m) - returns a list, because maps are not sortable by value (and the default is not sortable at all)

✔️ 4
4
manas_marthi19:08:33

thanks a lot!!

pauld19:08:56

I've never had any issues with needing to rebind local contexts - but I believe yurt solves that.

pauld19:08:11

I just like how easy it is to use and reason about.

pauld19:08:22

less work getting started.

pauld19:08:15

But I think tolitius can better explain. I just wanted the simplest way to make my code reloadable and to give me fine-grained control over app state during development and mount fit the bill.

👍 4
placeboza19:08:54

It does seem prettier and easier to get going with. But just a little less configurable wrt context

pauld19:08:24

yeah, just fit my brain easier

noisesmith19:08:20

when testing, it's the difference between initializing or mocking / overriding globals (mount) vs. providing the component with stubs of its deps (usually hash-maps and (constantly foo) functions) with component

noisesmith19:08:04

making things stateless as component requires isn't free design wise, but it has some nice consequences

noisesmith19:08:08

also with component, you can use an injected dependency from an upstream user of your code (it's just a value passed in at runtime) (this might also work with mount, but with component there's no "trick" to it - it just works like any other component and does the right thing)

placeboza19:08:25

There's also Integrant, but doesn't look like the right direction for my brain

noisesmith19:08:19

Integrant strikes me as an attempt to do stuartsierra/component but with more magic just-do-the-right-thing convenience (that said, I haven't used it in anger)

placeboza19:08:17

The examples just made my eyes glaze over 🙂

placeboza19:08:37

Maybe once I am familiar with the others it would make more sense to me

placeboza19:08:07

I think a lot of my issue is unlearning my 20+ years of non-Lisp/FP experience

placeboza19:08:44

My instinct is to use this or that pattern of non-functional concepts

placeboza19:08:02

So perhaps what I need to learn is the common patterns that lispers use when building a system

placeboza19:08:36

Mainly to lower the cognitive load 😕

noisesmith19:08:52

a simple one that you'll see a lot is replacing f(x) which modifies y, with (f y x) which returns a new value for y (along with any other return value needed)

noisesmith19:08:53

there's actually a proof that any global mutable can be replaced with an argument that is added to the input list of every function, and returned as an extra value from every function

👍 4
pepas19:08:48

If you were to undertake the quixotic quest to port a Clojure to run on top of Swift/iOS, (with the goal of learning, not with the goal of actually producing a working result), what approach would you take? Would you port Clojure itself (replacing all of the .java files with .swift implementations), or take the ClojureScript approach and write a Clojure->Swift compiler? Why? For either answer, what is the very first step you would take (i.e. which source file would you start examining / porting)?

noisesmith19:08:05

the main difference of jvm clojure and js clojure is that jvm clojure outputs byte code from the compiler, and cljs emits js from the compiler

👍 8
pepas19:08:07

Ah, and there is no equivalent concept of bytecode in Swift, which perhaps changes things

4
noisesmith19:08:29

what does the swift runtime do, load code at startup?

noisesmith19:08:43

anyway, sounds closer to js from that

pepas20:08:37

Yeah, I'm not sure. I was guessing that emitting swift might make more sense, because it already has support for immutable value types (structs, enums, etc).

noisesmith20:08:59

if you find out you want to emit bytecode, you could look at how clojure-clr is done, if you wanted to emit swift source, then look at the main (non-bootstrap) cljs compiler

4
noisesmith20:08:42

I have a hunch that you'd find things that don't quite match up with clojure's immutable data structures and swift's such that you need to make compatibility wrappers anyway - I don't know enough about swift to say for sure though

pepas20:08:57

@noisesmith so I'd maybe want to start with looking at comp.clj, shown in this diagram? http://blog.fikesfarm.com/posts/2015-07-17-what-is-bootstrapped-clojurescript.html

noisesmith20:08:46

well I meant to indicate the non-bootstrapped cljs (the one written in java), I assumed that there would be less to change

pepas20:08:48

@noisesmith yeah, now that I think of the idea of building "persistent" datastructures, I'm not sure that starting with a building-block of an immutable value (as opposed to an object) is any help

noisesmith20:08:56

but if bootstrapping is a goal you could look at that, sure

pepas20:08:16

yeah, I believe that page is indicating that comp.clj (in the first diagram) is the non-bootstrapped java implementation which spits out js.

noisesmith20:08:57

I may have been side-tracked by the page title

👍 4
pepas20:08:33

thanks for the kick! time to roll down hill...

placeboza20:08:47

FYI, this helps me a bit wrt grokking the change of design from C# to Clojure: http://mishadoff.com/blog/clojure-design-patterns/

placeboza20:08:55

Spoiler = standard design patterns are a bit moot in Clojure but that page illustrates it

orestis21:08:19

@jasonpepas see also tools.analyzer if you are looking to build a clojure compiler. I just listened to a cognicast episode about it...

👍 4
😀 4