Clojurians
#clojure
<
2015-11-26
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

eraserhd04:11:04

Looking for some kind of parser or FSM. So far, I can’t use instaparse (I need to be able to update with individual input elements and test for accept state and I need to process inputs that aren’t chars). Automat will work, but it seems kind of difficult to compose reducers. Any options I should look at?

mikethompson04:11:24

Or if you need just a FSM, you can simply code your own fairly easily (although you appear to need a parser): https://github.com/Day8/re-frame/blob/master/src/re_frame/router.cljs#L131-L170

eraserhd04:11:03

@mikethompson: reduce-fsm seems pretty promising.

eraserhd04:11:48

Hrmm. Same problem with reducers.

eraserhd06:11:10

After playing with reduce-fsm, automat, and instaparse, I think a hand-rolled state machine is the best option.

borkdude06:11:41

what is the comparable story in clojure with Akka Streams?

malch07:11:55

@borkdude: core.async? (probably)

danielgrosse07:11:35

How could I get a parent vector, which child has a specific string in it?

danielgrosse07:11:06

[vectortoget [„stringtosearchfor“]]

johanatan07:11:17

@danielgrosse: (map first (filter (fn [[parent [child]] (= child sought)) vectors))

danielgrosse07:11:28

Okay, thank you. I will try it.

roelof10:11:03

Hello, I want to try to make my first toy programm where I can keep track what in my wallet

roelof10:11:57

as far as I understand I can use a atom to keep track of the amount and swap! to change it when I give money out for something or put some money in my wallet

roelof10:11:09

Now I wonder if I can use compare-and-set so I know every transition is take care the right way

roelof10:11:29

anyone who has a tip/hint for this ?

jaen10:11:36

Can you describe what exactly would you want to guard against?

rauh12:11:58

Can I rely on iterate being unchunked?

roelof13:11:33

@jaen: guard against that if I make it bigger so multiple people can work with it that the transactions will be in the right order.

rauh13:11:04

@robert-stuttaford: Thanks. No IChunkedSeq so I guess I'll assume it'll stay like that.

jaen13:11:04

@roelof: can you define what right order means? For example by giving an example of what would be right order and what would not be. I'm just trying to understand what exactly are you after.

roelof13:11:35

@jaen : just a example out of my head. Suppose you have a bank-account with amount 0 , Now one person makes a deposit of 100 euro and another person pays a bill of 50 euro. At this order no problem. 0 + 100 = 100 -50 = 50. If the system first pays the bill there is a problem because amount is not allowed to be less then zero.

roelof13:11:17

This toy project is a very simple example of a accounting system which I want to make with clojure in the future

jaen13:11:44

So that's basically the same use-case SQL transactions solve.

jaen13:11:57

So you have more than one option

jaen13:11:58

For example

jaen13:11:01

You can keep all accounts in a single atom. Like so

(def accounts (atom {12 {:amount 100} 14 {:amount 50}}))

(defn transfer [id-from id-to amount]
  (swap! accounts (fn [accounts]
                    (-> accounts
                        (update-in [id-from :amount] - amount)
                        (update-in [id-to :amount] + amount)))))

jaen13:11:25

All calls to swap! on a single atom are serialised

jaen13:11:58

So no transfer will see a the accounts in an inconsistent state.

jaen13:11:16

Of course that's without any checking whether the transfer is valid, but I guess you can see where you can do that (inside the fn given to swap).

jaen13:11:31

The downsides here are twofold

jaen13:11:01

First, this reduces concurrency - even if you have thousands of accounts, only one account can be updated at a time, so this won't scale to many accounts.

jaen13:11:09

It's good enough for a toy project though.

jaen13:11:37

Another is it's a bit hard to return a value that signifies whether the transfer succeeded or not.

jaen13:11:53

You could probably work around it with an additional atom, like so

jaen13:11:06

(def accounts (atom {12 {:balance 100} 14 {:balance 50}}))

(defn transfer-valid? [{:keys [balance] :as account} amount]
  (>= (- balance amount) 0))

(defn transfer! [id-from id-to amount]
  (let [successful? (atom false)]
    (swap! accounts (fn [accounts]
                      (if (transfer-valid? (get accounts id-from) amount)
                        (do
                          (reset! successful? true)
                          (-> accounts
                              (update-in [id-from :balance] - amount)
                              (update-in [id-to :balance] + amount)))
                        accounts)))
    @successful?))

eugene13:11:32

Hey guys, is it possible to use [org.clojure/data.json "0.2.6”] to parse only the first level on a JSON object and not go for nested ones? For instance I’ve got this kind of incoming string:

{
                "instance_ID": "%INSTANCE_ID",
                "instance_IP": "%INSTANCE_IP",
                "postDate": "%date{yyyy-MM-dd'T'HH:mm:ss.SSS}",
                "body": "%m",
                "level": "%-5level",
                "thread": "%thread"
                }
and “body” field content should be treated as a string without attempt to be parsed. Is there a way to do this?

jaen13:11:01

@roelof: A somewhat better idea would be to use would be to use refs and transactions (`dosync`) where accounts can be separate refs and it all behaves like SQL transactions with separate refs being separate rows and you have sort-of row-level locking.

roelof13:11:07

jaen: thanks, Im getting the idea

jaen13:11:44

You can look them up, if you have "Programming Clojure" or "Joy of Clojure" on hand both describe those concurrency primitives rather well.

roelof13:11:25

@jaen: thanks, I have seen refs and dosync already on the clojure koans

jaen13:11:54

Yup, the main difference is

jaen13:11:02

You can't coordinate two atoms with a transaction

jaen13:11:07

But you can do that to two refs

roelof13:11:47

Like here : https://www.refheap.com/112099 but I got confused by linenr 9

roelof13:11:24

how to combine the first and the second function

roelof13:11:07

I do not have any of those two book at hand but I can look them up

roelof13:11:41

I heared Programming clojure is better for a beginner then joy, @jaen

jaen13:11:15

Yeah, "Programming Clojure" is from the basics book

jaen13:11:24

Pretty cool and has a swan on the cover

roelof13:11:44

I found it. And if I look at the contents chapter 5 is what im looking for

roelof13:11:17

now see if I can take care that I have it for my own

roelof13:11:43

@jaen: thanks for the help so far

jaen13:11:51

If you read the chapter carefully it should be relatively easy

jaen13:11:05

Especially if you had prior experience with SQL transactions

jaen13:11:10

Since it's quite analogous

roelof13:11:23

oke, thanks

roelof14:11:25

another this time beginners question : What do I have to change so this code https://www.refheap.com/112089 is outputtting [ 1 1 2 2 ] instead of [ ( 1 1 ) ( 2 2 )]

jaen14:11:18

How about (defn [list amount] (mapcat #(repeat amount %) list))?

jaen14:11:42

Though keeping as close to your example

jaen14:11:44

You're doing something equivalent to

jaen14:11:18

(conj [1 2 3] 4 5 [ 7 8])

jaen14:11:20

Which results in

jaen14:11:27

[1 2 3 4 5 [7 8]]

jaen14:11:42

conj treats each argument it's given as a singular item to add to the collection

jaen14:11:15

So if you conj [7 8] it will end up there as the vector it is, it won't be splatted into the collection

jaen14:11:36

On the other hadn, if you have some collections you can use concat

jaen14:11:40

It will joins the collections

jaen14:11:02

(concat [1 2 3] [4 5] [7 8]) results in (1 2 3 4 5 7 8)

roelof14:11:11

oke, so my conj was wrong. I still have a lot to learn

jaen14:11:19

So you can use concat instead of conj and it will work, yeah. concat - joins collections/sequences, conj - adds elements to a collection/sequence.

jaen14:11:33

Just read the docstrings carefully

jaen14:11:42

It should help if you understand what each function does exactly

jaen14:11:49

Also play around with the function in REPL

roelof14:11:53

I think I still have to spend a lot of time to 4clojure

jaen14:11:57

to see how it behaves if you give it different things.

roelof14:11:08

and forget a while about my toy project

jaen14:11:04

I think toy projects are important as well, it also forces you to face new things

roelof14:11:45

Correct, but it looks like I still have problems to find out which function I need for a particular case

roelof14:11:51

@jaen: thanks, this one works fine : (reduce #(concat %1 (repeat amount %2)) [] list))

danielgrosse14:11:32

I have a function call with arguments in the format {:call-id 12, :options {}, :seq-args [1 2], :map-args nil}where :seq-args the args contains, which the bound function needs. How can I bind the function, so I could use a normal definition like (defn fn[x y](println x y)) ?

jaen14:11:40

@roelof: yup it does, but I think the solution with mapcat I suggested above is clearer. If you see why it works then I think it's better.

roelof14:11:10

I know mapcat , I tried if before but with no success

jaen14:11:38

mapcat is basically (apply concat (map ...))

jaen14:11:42

That is it does map

jaen14:11:48

And then concats all the results

roelof14:11:50

and I wanted to challenge myself to find a answer with reduce because the former challenge could also be done with it

roelof14:11:31

what do you mean with Gotcha ?

jaen14:11:45

"Got it" as in "I understand"

roelof14:11:12

thanks again then , jaen

jaen14:11:34

Though clever is not always clearer, figuring the solution with reduce is smart, but I had to look at it twice before I understood what you wanted to do.

roelof14:11:41

I love this community because they treath newcomers

roelof14:11:59

I hope I wrote it down well

roelof14:11:26

Always someone who is willing to learn a newcomer things

jaen14:11:06

I wouldn't know, I always learned things on my own, but if you feel that way about here, then that's nice

roelof14:11:03

@jaen: I try to learn also on my own but sometimes I get very stuck

roelof16:11:43

Do I have to change something here : (some #{2 7 6} [5 6 7 8])) I get now a symbol some not found error message

jaen17:11:23

You have one paren too many at the end, maybe you're closing something you shouldn't and that changes the scope somehow? Other than that looks good and works in my REPL.

roelof17:11:28

wierd, I do not work in the repl of Cursive but I will try again

roelof17:11:41

jaen , I see this output :

roelof17:11:42

Starting nREPL server... Connecting to local nREPL server... Clojure 1.7.0 nREPL server started on port 64691 on host 127.0.0.1 - <nrepl://127.0.0.1:64691> (some #{2 7 6} [5 6 7 8]) CompilerException java.lang.RuntimeException: Unable to resolve symbol: some in this context,

jaen17:11:14

I don't know, you're using Windows, maybe Windows is doing something weird as it is known to do. Does it work if you run the repl from the command line?

roelof17:11:17

then I see as output 6

jaen17:11:00

Hmm, ok so maybe something's wrong with your Cursive setup then. How did you set it up?

jaen17:11:16

How did you create the project, ran the REPL and so on.

roelof17:11:17

wierd, I was expecting to see 7. That one is earlier in the first {}

jaen17:11:41

I get 6 as well, 6 is first in [5 6 7 8].

roelof17:11:59

I imported it in Cursive

roelof17:11:31

maybe I can try a clean project

jaen17:11:34

If you imported then I assume you have a project.clj?

jaen17:11:53

How does it look?

roelof17:11:01

a project.clj from a earlier project

jaen17:11:41

That doesn't tell me much : V

jaen17:11:48

But maybe try a clean project as you say

roelof17:11:16

oke, so some looks at the order of the second {}

jaen17:11:52

Basically some works like this

roelof17:11:55

after dinner I will make a clean project

jaen17:11:04

(some predicate collection)

roelof17:11:06

and look if its working fine then

jaen17:11:15

Where a predicate is a function that returns true or false

roelof17:11:21

if not, then a message to the cursive people

jaen17:11:25

And it will return the first item of collection

jaen17:11:33

That the predicate returns true for.

jaen17:11:35

(some a-set collection) is a common Clojure idiom due to the fact that Clojure collections can be called as a function to return an item.

jaen17:11:00

([1 2 3 4] 2) will return 3 (element of vector with index 2), ({:a 1 :b 2} :b) will return 2 (value of map under the key :b) and (#{1 2 3} 3) will return 3 (it returns the value if the set contains the value; if you did (#{1 2 3} 4) you would get nil).

jaen17:11:31

Basically it's equivalent as if you did

jaen17:11:08

(some (fn [x] (contains? #{2 7 5} x)) [5 6 7 8])

jaen17:11:27

But most Clojurists will think (some #{2 7 6} [5 6 7 8])) is more concise (and clearer to read)

roelof18:11:09

oke, thanks for the explanation

roelof18:11:30

@jaen : on a clean project some works well

roelof18:11:37

also there 6 as answer

jaen18:11:17

Heh, curious what broke it.

roelof18:11:48

now the next challenge of 4clojure , implement range

roelof18:11:18

without using range so ( 1 4) gives ( 1 2 3)

roelof18:11:08

so time to think how to do that, so please at this moments, no hints

cfleming19:11:51

@roelof: Are you sending that form from an editor to the REPL, or typing it into the REPL window?

cfleming19:11:49

@roelof: @jaen: The problem is that Cursive will execute forms sent from the editor in the namespace of the editor, not the current namespace of the REPL.

cfleming19:11:48

If you haven’t loaded that namespace into the REPL yet it has not been correctly initialised and will not have clojure.core forms referred yet.

cfleming19:11:40

You can see the same thing happen in a lein REPL if you do (in-ns ‘some-ns) and then execute something - in-ns does not initialise the namespace like ns does.

roelof19:11:49

@cfleming: Im sending it from the editor to the REPL

roelof19:11:23

it worked when I make a clean project and open a repl and send it then to the REPL

bensu22:11:12

does anybody know how to specify the lein version to be used in travis ci?

bensu22:11:58

:min-lein-version "2.5.2" gets me a warning