boop.core> (def m {:username "sally" :profile {:name "Sally Clojurian" :address {:city "Austin" :state "TX"}}}
boop.core> (get-in m [:profile :address :state])
"TX"
boop.core> (:state (:address (:profile m)))
"TX"
You have everything right except 'adress'. It's likely, as @caumond says, the spelling.
All the books can be found here https://practicalli.github.io/
Ah I didn't see it as a title in that big cluster of graphics! Yes, here's the web apps link directly for @mircoporetti https://practicalli.github.io/clojure-webapps/
Great list. I’ll add “Joy of Clojure” - one of my favorites. https://www.manning.com/books/the-joy-of-clojure-second-edition
Keep asking questions, the Clojure community is one of the biggest advantages to learning Clojure https://practicalli.github.io/blog/posts/cloure-community-getting-help/
I think most languages are niche, until one of three things happen: * A killer app in the language blows up: for example Rails put Ruby on the map. Spark put Scala on the map. Numpy put Python on the map. * A large company becomes the shepherd of the language. Google most famously pushed Python and Go. Mozilla pushed Rust. Twitter pushed Scala. Microsoft pushed TypeScript. * A platform forces its use. Swift and ObjectiveC for Apple. C for linux. JavaScript for browsers. Java/Koltin for Android. C# for Windows and Unity.
All very good points. JavaScript is a particular good example. I don't think JavaScript was considered a serious language for a long time. Then jQuery came along (which still seems the most used library). Then more business got behind the language (even Microsoft) and of course every companies started using JavaScript for front end websites. Then node and mom came along... Although there are no guarantees that a language grows even with a 'killer app` or company support (i.e Dart from Google) or enviable platform changes. I am enjoying the diversity in languages we have experienced, even though it can add a burden to keep up. This diversity does encourage developers to thing differently about the software they write. This thinking is beneficial to Clojure as there are many subtle and important differences to discover
hello all, I am trying to make an app in cljs (with reagent) and it needs to interact with an API that's being hosted by a django backend. Is there a way to do the neat little development environment but somehow proxy all my requests to the django backend?
In this video, there's a quote from Rich Hickey and the presenter says that if there's one thing to be taken away from the talk, it should be that:
When you combine two pieces of data you get data. When you combine two machines you get trouble.
I understand what this means (I think). But can someone explain why this has to be stated explicitly? Or what's the context in which this was quipped by Rich Hickey?
https://www.youtube.com/watch?v=C-kF25fWTO8@dan.yb.tobias IIUC your django backend will be the only web server, right? then just tell your build tool to put the generated javascript somewhere that your django backend will know to serve
in principle it's not very different to working with a Clojure backend
doesnt figwheel or whatever spin up a little development server?
i dont want to have to compile every time i make a change etc
that's independent of the server that actually serves your main web page
ty
if you serve a html doc like the one described in that page from your web server, and if your web server serves the right file when asked for "/cljs-out/dev-main.js", you should be good
It comes from here: https://www.infoq.com/presentations/datomic-functional-database/
14:48
Hi everyone, I'm not sure where I should ask this but am trying to get the automated testing for clojurewerkz/money working again.
Seems like at least for openjdk8 all tests pass but am encountering Tried to use insecure HTTP repository without TLS
as shown here https://travis-ci.org/github/clojurewerkz/money/builds/753470823
Understand that this is the result of the snapshot deployment link for Nexus, but does anyone know what link i should update it to in the project.clj here - https://github.com/clojurewerkz/money/blob/master/project.clj#L19
Transcript is here if you prefer reading: https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/FunctionalDatabase.md
@zackteo Change http://
to https://
?
Hey guys and girls. New to Clojure, I'm learning by writing clojure to solve problems at http://projecteuler.net. I just solved #3 using Clojure and I'd like to get some advice and tips about how I could've written my code better. Here's a gist, lmk if the link works: https://gist.github.com/orpheus/e803cb8fb90f925fda90b07576273741
Also, there's an error I could use help debugging with the getFactor
function, if passed 6857
(`getFactor 6857`) there's a stack overflow that I'm not sure how to go about solving.
You might also want to look at https://www.4clojure.com/ which has problems designed to help you learn the language.
@seancorfield thought about that. Guess I could give that a try. Was thinking if the link was meant to be inaccessible
@titanroark a quick thing to try would be to replace recursive calls to getFactor
with recur
: https://clojuredocs.org/clojure.core/recur
Thank you, this is the kind of advice I was looking for
im a bit confused here, the doc linked doesnt say anything about it
do i need to change the port of the ring server to match as well?
also, to find factors you only need to check up to the square root... but now we're talking math. if your current primary focus is learning Clojure, http://projecteuler.net problems may have the focus too much on the math side?
I am so confused, am i running fig:build or what?
factorial is a different math concept. stick to the name "factor"
euccastro i think what you suggested before isnt quite right
lines 8-11 are the same as line 14, just specialized for the number 2. you could just call (getFactor x 2)
at that point
your django server would replace the ring server. it doesn't matter what port it listens on, as long as you visit localhost:<that-port> in your browser
you can run any regular figwheel command
sorry, I had missed your reply; I've just replied in that thread
there is no html file produced though?
oof this is not working at all, i made an html and loaded the js there but
I did some Project Euler problems some time ago. You can find here: https://github.com/nakiya/euler/blob/master/euler.clj Just check for problem 3
@euccastro it looks like how the js is trying to load files is bad...it's using escape charatcers in strings?
Wow it did work. Guess i should have just tried that
https://github.com/jstaffans/django-cljs-loader i got it working using this
Not sure if this falls under beginners but has anyone encountered a situation where a new github pull request (that just changes the readme breaks the existing clojure tests? CI on github actions) https://github.com/zero-one-group/fxl/pull/31/checks?check_run_id=1666803003 It is very strange. Because when I try rerunning the tests on the previous commit there is no issue. But once I make a new pull request, even in the minimal example just amending the readme, breaks the CI
It's possible the tests are non-deterministic or something in the tests is not compatible with the GitHub Actions environment...
hmmm, my issue is that it would make sense that the github actions doing the test would have failed for the previous commits then or failed when I reran the actions but no issues
It is just generally quite an odd situation
Computers are deterministic by definition 🙂
My own theory is that the github secrets might be having issues when I am the one pushing the commit
Tho I am not sure if that theory checks out with the github actions history :thinking_face:
In which it should be intermittent and kicking off the process again should succeed...
Oh I mean the owner of the repo might be the only one able to access the secrets - I can't tell if that makes sense
I do know that this exists tho https://github.blog/2020-08-03-github-actions-improvements-for-fork-and-pull-request-workflows/
guess all I can do is sleep on it
Do not know what is the right channel for pedestral questions so I ask here I have this :
`(ns hello
(:require [io.pedestral.http :as http]
[io.pedestral.http.route :as route]))
(defn respond-hello [request]
{:status 200 :body "Hello, world!"})
(respond-hello {})
deps.edn
{:deps
{io.pedestal/pedestal.service {:mvn/version "0.5.7"}
io.pedestal/pedestal.route {:mvn/version "0.5.7"}
io.pedestal/pedestal.jetty {:mvn/version "0.5.7"}
org.slf4j/slf4j-simple {:mvn/version "1.7.28"}}
:paths ["src"]}
but still I see this error :
; Execution error (FileNotFoundException) at hello/eval13893$loading (REPL:1).
; Could not locate io/pedestral/http__init.class, io/pedestral/http.clj or io/pedestral/http.cljc on classpath.
im following this tutorial now : http://pedestal.io/guides/hello-world
You have a typo, it's called pedestal, not pedestral. (Remove the r
)
FYI there's #pedestal
thanks
What am I not getting?
(defn vec-of-14 [& seqs]
(count seqs) ;=> 3
(->> seqs
(concat)
(take 14)
(vec)) ;=> Eval timed out!
)
(comment
(vec-of-14 (repeat 14 true)
(repeat 1 false)
(repeat true)) ;=> Eval timed out!
(->> (concat (repeat 14 true)
(repeat 1 false)
(repeat true))
(take 14)
(vec)) ;=> [true true true true true true true true true true true true true true]
)
So, the second form in the comment
there works as I expect. Trying to make a function from it blows up. The seqs are realized is my guess, but when and how and why?You probably need to replace (concat)
by (apply concat)
in your method.
Oh, of course… Thanks!
See that I have to learn a lot more about clojure to make my own sites and really understand how things really work
interceptors are I think the hard part
You don't need interceptors to make a site
Start simple
Pedestal bundles a few things together
If you find it hard to grok you could go a step back. I think the absolute minimum for a beginner is something like compojure and figwheel but it's best to ask around
maybe I will or go back to duct or take a few steps more back. Before pedestal I did a few tutorials about duct and before that about ring.
what would be the pattern if I basically want to block until a certain condition is true? I'm waiting on a file and the last-modification time keeps changing and I want to wait until it doesn't change any longer for 100ms or something
Your deps.edn looks fine. But you have a misspelling in your require. "pedestral"
thanks
So what exactly are the differences between `(filter #(<= 5 %) coll)` and `(filter (partial <= 5) coll)` ? Is that second example using a "transducer?"
From reading the home page docs I don't think so. I should be creating an "xform." I get the feel that transducers are the current trend in performant, idiomatic clojure but I'm mostly confused about it all.
Any resources you recommend to start thinking in the transducer way of doing things? I feel like that could (should?) be the next step in upping my fp game.
What initially inspired this is this reddit thread: https://www.reddit.com/r/Clojure/comments/kr0j0f/newbie_question_on_idiomatic_iteration/ I want to start thinking like how SimonGray and joinr handled the problem
neither of those are using transducers
I knew the first one wasn't, just wasn't sure if that second one was. I guess I don't really know what I'm asking besides how to start thinking in the higher abstraction, transducer sense of solving problems. Probably the only answer is experience.
read that guide and internalize what transducers are. i think its really important to remember they are functions that take reducing functions and return reducing functions
Will do. The embarrassing part is the first paragraph reiterates: Note: this reduced arity is not currying or partial application. And here I am asking if that partial
produced a transducer. lol
no worries. they can be a bit difficult to grok them. follow that guide and build up your intuition and also keep that definition in mind: a function from a reducing function to a reducing function
And are they more performant to use in most cases? I know that's probably to general to ask though. But is it something you usually try and reach for when writing idiomatic clojure?
at the top is a link for "good use cases for transducers" which has a section about performance. nothing more authoritative or thoughtful than that section
Fair enough! Thanks
again stuck how I have to deal with this :
; Implement update-in.
(def my-update-in [m k f]
)
I think at some way I have to find the part with the key and then apply the function at the value and put the whole m again together.
Do I thinking the right way ?Sounds like a good plan, yes. If by "put the whole m again together" you are thinking "create a new map in N steps if the original map m has N key/value pairs", then there are faster ways, e.g. "create a new map from m by replacing only the value of key k with the new value"
hmmm, then I have to think again
that could work but on some way I have to check where I want to check things
You could get a correct solution by creating a new map in N steps.
n steps ?
It probably just would not be among the fastest solutions.
Your original statement said "and put the whole m again together".
There are multiple things you might have meant when you said that, and I don't know what you were thinking.
that is not the most important I think. This is a challenge from the brave book and I think the purpose is to understand how things work
One thing you might have meant was "for each of the N keys in the original input map, add that key to a new map to be returned"
not find the fastest one
Lets say we have this map : (def users [{:name "James" :age 26} {:name "John" :age 43}])
That is a vector containing two maps.
oke
another one then :
{:name "James" ;age 26}
That is one map 🙂
now I want to change the age to 36 because I made a typo
sure
then my idea was to use for example `get to get the age out of it
sounds good
make a new age with 36
yep
and then I have to make a new map with the name part and the new age part
yes
or if I want to change the name a new map with the new name and the old age part
but I think I do not see how the pieces comes together
My only point was that there is more than one way to do that last step, and I was making a comment about efficiency of a couple of different ways. If you aren't worried about efficiency at all, then by all means ignore that comment.
I think I have to store the new part somewhere with a let ?
I wouldn't say "have to", but if it helps you write a solution, then let
is perfectly reasonable.
(def my-update-in [m k f] (let [new_value (f (get m k)] )
If you want to use let
, then taking your breaking the function up in to steps, you can first get the current value in the map for key k
, and bind that result to some new name in the let
, e.g. cur-val
or whatever you would like to call it.
Sure, what you do there is doing your first two steps in one line, which is also good.
oke , if I go to fast , say it please
I will. Don't worry, I'm following so far 🙂
then I have to make a new map. I think I need to use assoc
but how do I now from the old map what is then the old part ?
and what is the new part?
So assoc
always returns a new map, leaving the original one unchanged. The new map is almost the same as the input map, except for the value associated with the key you give to assoc
, which in the returned map will be the value you give to assoc
yep, so there im stuck
user=> (assoc {:a 1 :b 2 :c 3} :b -2)
{:a 1, :b -2, :c 3}
oke, so I do not have to know
I didn't tell assoc to do anything with keys :a or :c, and the returned map still has them, associated with their original values.
That is what assoc
is intended to do.
oke, did not realize that
Has the book you are following described assoc
before this exercise, I hope?
so I can do just this :
(def my-update-in [m k f]
(let [new_value (f (get m k)]
(assoc m new_value)
)
yep, I did
but I think I misunderstood it as just for adding things
Your call to assoc
doesn't have the correct number of parameters.
(def my-update-in [m k f]
(let [new_value (f (get m k)]
(assoc m k new_value)
)
that looks better
Looks like a good time to try out your new function with some sample input parameters in a REPL and test if it works as you hope.
there is still a error somehow
What editor are you using?
calva is yelling me that the closing ] is on the wrong place
I use vs code with calva
Most editors have the option to show you when parens, square brackets, or curly braces are matching or not. You definitely want to get familiar with how to understand what it is telling you there.
Anyone using cider with Doom emacs? Trying to figure out the most appropriate way to evaluate the form under the cursor
e.g. many editors will show you the matching paren, bracket, or brace when your cursor is on or just after one of them, highlighting it visually so you can see which one matches the one where the cursor is.
yep, I was missing a )
Trying to write a Lisp-like language without such editor support is going to slow you down tremendously.
There is a lot of fancy 'structural editing' stuff you may have heard about that some people love, but I've never used that myself. But I do really, really miss it if I ever use an editor that doesn't show me matching parens and brackets.
still somewhere a error :
; Execution error (ClassCastException) at chapter5/my-update-in (form-init95645667318631163.clj:51).
; class java.lang.Long cannot be cast to class clojure.lang.IFn (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')
code :
(defn my-update-in [m k f]
(let [new_value (f (get m k))]
(assoc m k new_value)))
(my-update-in p :age 35)
Is there anything else in the same file with that function? Looking at the function definition, nothing obviously wrong jumps out at me.
What is the 3rd parameter of my-update-in supposed to be?
Im my first idea it was a function but later it changed to the new value
What does my-update-in
do with the 3rd parameter?
it uses it to make the new map with a updated key
so it is not a function
The only place the 3rd parameter is used in my-update-in
is this expression (f (get m k))
So it is trying to call f
as a function.
yep, I see it , thinking how tto solve it
That is what the exercise asked you to write, I think, yes?
Then when you are trying to use my-update-in
, you gave it the number 35 as the 3rd parameter, and my-update-in
tried calling the number 35 as if it were a function.
So it appears to me that your my-update-in
is doing what the exercise says it should, but your attempt to call the function is passing a 3rd parameter that it was never intended to handle.
i.e. you are calling my-update-in
incorrectly. You should try calling it where the 3rd parameter is some function.
If you want a quick try, replace 35 with inc
, which is a function.
I'm using it with lispy[ville] and lispy-eval keybinding (iianm I had to add com.cemerick/pomegranate
and com.billpiel/sayid
to my clojure deps for it to work)
yep, that works
Does it make sense why you got the error when you passed in 35?
it makes sense
Do you know how to write a Clojure function that takes a number and adds 10 to it?
yep
defn add-ten [number]
(+ number 10))```Good. If you define that function, you could pass add-ten
as the 3rd parameter to my-update-in
oke, so there is no way I could make it work without a function ?
only given the right value
You could write a different function than my-update-in
that takes a new value for the 3rd parameter instead of a function.
If you did, I would call it my-assoc
🙂
I was thinking to change my_update_in
If you change my-update-in
to take a value instead of a function as the third parameter, you can certainly do that. Note that it would not be one that solves the exercise you were working on.
?? the only that the challenge said it to implement update-in
Yes, I understand that.
YOu asked if you could change my-update-in
to behave differently. You can do that if you want.
I am only saying that such a changed my-update-in
does not solve the challenge.
oke, I see it, update-in takes always a function
as the 3rd parameter, yes.
so I wanted to make another function
And I encourage you to experiment to your heart's content 🙂
thanks for thinking with me and teaching me some things
no problem
clojure is a totally other beast then when I was learning ruby or haskell
but I love the way repl helps me to see the results when I try something
You could write my-update-in
in Haskell in about the same number of characters, I suspect. Clojure and Haskell share that they deal mostly with immutable values, but Haskell has far fewer "escape hatches" than Clojure does for mutating state.
And Clojure doesn't restrict you to writing code that passes Haskell's type checker.
and clojure is much faster then a haskell programm is my feeling
and I played with some web stuff and clojure has much more choices then haskell
in haskell you have only yesod and servant as big players
I don't know a lot about Haskell performance to compare it to Clojure -- they both are not necessarily the language you want to use to get the best performance for heavy numerical computation, for example.
clojure has for back-end duct, pedestral en some more
but both are perfectly fine for calling out to libraries written in other languages for doing that kind of thing.
but much more to do for your own
dinner time
and tomorrow or later time to study the next chapter macro's 🙂
Apart from that and cider-eval-…
bindings as well as cider-pprint-eval-last-sexp-to-comment
I so far have found cider debugger with enlighten-mode quite useful. Seeing how flexible this all is I'd be also interested in seeing what others are using for quick & easy inspection of forms & values 🙂
I moved away from lispy because of le-clojure.clj. I use cider-eval-defun-at-point
and cider-eval-last-sexp
... If I ever need to be more granular, I use er/expand-region
and then cider-eval-region
... all these are bound to things like , e d
, e e
etc
Use while
These are the same
The only difference is that #(<= 5 %) creates the predicate function at read time, and (partial <= 5) creates the predicate function at run-time
The docstring you're reading is referring to the arity (number of arguments) of filter
Both your example call filter with 2 arguments though, so in your case you are using the 2-ary version of filter in both case
The doc says return a transducer when no collection is provided, and in both cases you provide [pred coll]
it really doesnt look like cljs works well with a django backend 😛
i am really struggling to get it working
The backend and front end are orthogonal. If you return Json the backend technology is irrelevant for cljs. Do you have a more specific problem you can share?
i think it's more about the project.clj file, im doing a figwheel-main reagent template and I guess i need to hook it up so that the project itself isnt necessarily in the django folders but the produced html/js/css ends up in the correct places
there's just like 2 million directories specified in this thing
looks like the configuration doesnt like relative paths either
damn
can you share your project.clj?
@b Are you're referring to the part of lispy provided by le-clojure.el
? Does it have some flaws one should be aware of?
(defproject livematch "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:url "<http://example.com/FIXME>"
:license {:name "Eclipse Public License"
:url "<http://www.eclipse.org/legal/epl-v10.html>"}
:min-lein-version "2.7.1"
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/clojurescript "1.10.773"]
[reagent "0.10.0" ]]
:source-paths ["src"]
:aliases {"fig" ["run" "-m" "figwheel.main"]
"fig:build" ["run" "-m" "figwheel.main" "-b" "dev" "-r"]
"fig:min" ["run" "-m" "figwheel.main" "-O" "advanced" "-bo" "dev"]
"fig:test" ["run" "-m" "figwheel.main" "-co" "test.cljs.edn" "-m" "livematch.test-runner"]}
:profiles {:dev {:dependencies [[com.bhauman/figwheel-main "0.2.12"]]
:resource-paths ["target"]
;; need to add the compiled assets to the :clean-targets
:clean-targets ^{:protect false} ["target"]}})
the main issue im having i think is the dev-main.js can't find any of the deps it needs for some reason
if i look at dev-main.js i have lines like this:
document.write('<script src="..\..\paladeenz\website\static\livematch\public\cljs-out\dev/cljs_deps.js"></script>');
notice the escape characters..
it's just copy and pasting the target directory..but remember the src is in a different folder than my django app...so when the js gets put into the django app it needs to look in the correct place for the deps but isnt
what’s dev-main.js?
where is this file? and what’s suppose to do?
this is the output js from building...i fixed it by editing all of the urls the issue is that if recompiled it will overwrite and i have to change it over and over
ohh ok…
the target-dir i set is so that it can create dev-main.js in the correct spot, but dev-main itself seems to be using the target-dir also to find the dependencies which completely breaks it
so i have a figwheel-main.edn file which says
:target-dir "../../paladeenz/website/static/livematch"
which puts dev-main.js where it needs to be..it's just now dev-main.js is trying to load files from target-dir + other stuff, which is wrong
https://figwheel.org/config-options#target-dir idk if there's anything in here to fix that
it’s long time since i use fighweel.main but let me see if i can find something
im going to try adding in output-to and output-dir
NVM it didnt like those keywords haha
it's like this stuff is designed to be as cryptic as possible
did you try maybe asking in the #figwheel-main channel, i think somebody with more experience than me will be able to help you (and wife is screaming at me now 8:30 pm now :D)
ok ill ask there, ty
What is here wrong ?
(defn my-update-in [m ks f args]
(assoc m ks (apply f (get m ks) args)))
(my-update-in p [:1] :age inc)
error :
; Execution error (IllegalArgumentException) at chapter5/my-update-in (form-init95645667318631163.clj:51).
; Don't know how to create ISeq from: clojure.core$inc
you specify f before args, then :age before inc
also (get m ks)
is weird - it's as if you expect the whole seq of keys to be one key
neither :age nor inc are collections, so neither works as a last arg to apply
I will sleep about this one :
(defn my-update-in [m ks f & args]
(let [[[k & ks] ks (assoc m k (apply f (get m ks) args))]])
error ;
; Syntax error macroexpanding clojure.core/let at (chapter5.clj:51:3).
; [[[k & ks] ks (assoc m k (apply f (get m k) args))]] - failed: even-number-of-forms? at: [:bindings] spec: :clojure.core.specs.alpha/bindings
grrr. now again a wierd error
(defn my-update-in [m ks f & args]
(let [[k & ks] ks]
(assoc m k (apply (get m k) ks f args))))
(my-update-in m [:1] assoc :value 1 :active true)
error:
; Execution error (ArityException) at chapter5/my-update-in (form-init6180925798125192449.clj:54).
; Wrong number of args (6) passed to: c
I always thought that & args
was taking in all the arguments that were left
So why still a argument errorand when im using our code from yesterday
(defn my-update-in [m keyword number]
(assoc m [number keyword] "not-found"))
it added a new value instead of chancing itHmm,
This works with the m variable but not with the p variable
(defn my-update-in [m keyword number function]
(function (get-in m [number keyword]) ))
(update-in m [:1] assoc :value 1 :active true)
(def p {:name "James" :age 26})
(defn add-ten [number]
(+ number 10))
(my-update-in p add-ten)
I see a arityException 😞
or when I do this :
(defn my-update-in2 [m keyword function]
(function (get-in m keyword)))
(my-update-in2 p :age add-ten)
error :
; Execution error (IllegalArgumentException) at chapter5/my-update-in2 (form-init4877412091744917773.clj:57).
; Don't know how to create ISeq from: clojure.lang.Keyword
get
and get-in
are different. You are giving get-in
a single keyword, when it expects a sequence of key values.
That comment was for my-update-in2
Remember, one way to debug these things is to evaluate expressions step-by-step, and see which one goes wrong, or returns a value you do not expect.
For the call to (my-update-in p add-ten)
giving an arityException, well, count the number of args in this definition, and how many you gave in your call: (defn my-update-in [m keyword number function]
In experimentation like this, it might be less confusing to leave earlier experimental functions that you consider working unchanged, and create new names for new experiments. I am not sure if that is part of the difficulty here for you or not, but thought I would suggest it.
Regarding your earlier question today: "I always thought that `& args` was taking in all the arguments that were left
So why still a argument error". Because some other function besides my-update-in
is being called with the wrong number of args. argument errors can happen for any function called with the wrong number of arguments, not only for ones that you define yourself.
Look for another function that is being called with the wrong number of arguments. Again, I would recommend trying to evaluate sub-expressions step by step, seeing what values they return, and continue step-by-step, and you should be able to get to the answer of which function call is throwing the exception because of wrong number of args.
If you never try to break down these things step by step, I don't know how else to help you learn how to discover what is going wrong.
oke, I will then try to debug this :
(defn my-update-in2 [m keyword function]
(function (get-in m keyword)))
where I see this error :
; Execution error (ClassCastException) at chapter5/add-ten (form-init4877412091744917773.clj:62).
; class clojure.lang.Keyword cannot be cast to class java.lang.Number (clojure.lang.Keyword is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')
clj꞉chapter5꞉>
my idea is that there is a argument missing in the get-in
part
yep, when I do (get-in p :name)
I see the same error
where p is (def p {:name "James" :age 26})
So, what do you know about the arguments that get-in
should be given?
but no idea was should be missing
What is the difference between get
and get-in
?
I do not have a key before the :name
`
If it helps you remember, create working examples of both get
and get-in
that you put in some personal notes for each function, maybe plus a sentence or two explaining the difference between them.
oke,
both are working
(defn my-update-in [m keyword number function]
(function (get-in m [(number keyword) keyword]) ))
(defn my-update-in2 [m keyword function]
(function (get-in m keyword)))
so I now know if there is a number given I need get-in and otherwise I need getIn case it helps, my personal thinking on this to explain their difference would be like so: "get takes a map and a single key to be looked up, or a vector and a key (integer index) to be looked up, and returns the value associated with that key, or nil if the key is not found"
yep
"get-in takes a sequence of keys to be looked up, and if that sequence is N elements long, it behaves like N repeated applications of the function get
where each repeated application of get
is applied to the collection returned by the previous call to get
."
so it looks I need a function with 2 things in it one for 4 arguments and one for 3
Thus (get m k)
and (get-in m [k])
behave exactly the same as each other.
BRB, wife needs the computer
sure
In what way does the my-update-in2
function you show above "work"?
As in, can you give an example call where it does what you want?
of course :
(def p {:name "James" :age 26})
(defn add-ten [number]
(+ number 10))
(my-update-in2 p :age add-ten)
gives : 36
chips the old one needs to be added
the other one :
(def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}})
(defn my-update-in [m keyword number function]
(function (get-in m [(number keyword) keyword]) ))
(defn my-update-in2 [m keyword function]
(function (get-in m keyword)))
(update-in m [:1] assoc :value 1 :active true)
gives :
{:1 {:value 1, :active true}, :2 {:value 0, :active false}}
which is right
so for the second one back to the drawing board
Is your goal to write my-update-in
so that it can take a sequence of keys, like get-in
does? Or do you want to make it so it can take one key, or two keys, only?
first one key, later maybe more keys
So yesterday you had a working my-update
function that took only 1 key, and I thought worked, true?
my goal is still to make it work with this two :
(def p {:name "James" :age 26})
(def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}})
yep, and also for the m one we have a working version
for the p as far as I know we have not
or I have deleted it
So sorry if you've already said it clearly and I've forgotten, but what do you mean when you say "my goal is still to make it work with this two ...". What do you want the behavior to be? Stating what you want the behavior to be with inputs and desired return values can help clarify this (at least for me).
np
One way to clarify this would be to say: "I want to write my own version of Clojure's built-in update-in
function, that always returns the same values it does, given the same inputs."
we have two working versions
(defn my-update-in [m keyword number function]
(function (get-in m [(number keyword) keyword]) ))
(defn my-update-in2 [m k f]
(let [new_value (f (get m k))]
(assoc m k new_value)))
but I'm not sure if that is what you are trying to do, or not.
update-in works on this case : (def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}})
and update-in2 works in this case : (def p {:name "James" :age 26})
Do you mean Clojure's built-in function udpate-in works on that case, or do you mean one of your my-update-in functions works in that case.
Because if you use different names, I get confused which function you mean.
the code we wrote seems to work
The code you wrote is not called update-in
im talking about my written versions of update-in
So please use my-update-in to refer to my-update-in, because there is a Clojure built-in function named update-in
yep
sorry, I named it so because it otherwise make problems with the built in one
When you say my-update-in "works" in this case, you are only giving one of the parameter values, not all of them. It doesn't make any sense to me to only give one of the parameters of a function that takes 2 or 3 parameters, and say it works.
Its behavior depends upon all of the parameter values, not just one.
sorry for the confusion
Please give complete calls to those functions that you consider working.
oke
I know have this :
(def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}})
(defn my-update-in [m keyword number function]
(function (get-in m [(number keyword) keyword]) ))
(defn my-update-in2 [m k f]
(let [new_value (f (get m k))]
(assoc m k new_value)))
(my-update-in m [:1] assoc :value 1 :active true)
and get a argument error . I have to give 4 arguments and I provide 7
So what function do you want to write? Please try to state that clearly, otherwise the goal keeps changing.
You say that these functions do what you want, then you say that they don't do what you want.
yep, I see now that I use the built-in function not my own written one
stupid mistake
pfff, two days busy and not closer to the solution. Wonder if clojure is for me
I can't answer that for you. For solving a problem of writing a particular function, I may be able to help if I know what function you want to write 🙂
for now I want to make my own written update-in working
And you want it to behave the same way that Clojure's built-in function update-in
works?
yep, that is I think the purpose of the challenge
ok, so that makes the goal of what function to write pretty clear, because we have an existing function that we can make calls to, see what the return value is, and know that is what this new function should return. (or we can just read the code of update-in to see how it works, of course, but maybe not yet for this challenge).
It is OK to write multiple functions along the way that only do part of what update-in
does, of course, and there are multiple ways to break that down into steps.
we can even peek how it written but that feels to me as cheating
One way would be to first write a function that doesn't take the & args
part of the arguments that update-in
does, only the function f
as the last parameter, and see if we can make something that works like that part of update-in
. Only if you get that working first, then try to add the & args
part.
That is, try writing a function my-update-in
that takes only the arguments [m ks f]
and no others, and make it behave the same way as Clojure's built-in update-in
when given those arguments only.
We had that I think with this version
`(defn my-update-in2 [m k f]
(let [new_value (f (get m k))]
(assoc m k new_value)))
or do I misunderstood you nowwe wrote that yesterday
I am pretty sure that behaves like Clojure's built-in function update
, but it does not behave the same way as Clojure's built-in function update-in
Here are some examples to demonstrate why I think so:
(defn my-update-in2 [m k f]
(let [new_value (f (get m k))]
(assoc m k new_value)))
(def m1 {:a 17 :b 18})
(update m1 :a inc)
;; {:a 18, :b 18}
(my-update-in2 m1 :a inc)
;; {:a 18, :b 18}
(update-in m1 [:a] inc)
;; {:a 18, :b 18}
(my-update-in2 m1 [:a] inc)
;; Execution error (NullPointerException) at user/my-update-in2 (REPL:63).
;; Cannot invoke "Object.getClass()" because "x" is null
The function that you have called my-update-in2
behaves the same as Clojure's built-in update
for the example parameters shown above. It does not behavior the same as Clojure's built-in update-in
for the example parameters shown above.
If I were you, I would rename my-update-in2
to my-update
, since we know it doesn't behave like update-in
and at least in some cases, it does behave like update
oke
we did yesterday only check it on this : (def p {:name "James" :age 26})
The map I give is the same in all calls.
That is not the difference.
Do you see the difference in the parameters given to update
vs. update-in
?
I think so we gave it a key and on update-in2 fails when its a vector of keys
As I wrote above, the difference between get
and get-in
is that get
takes a single key but get-in
takes a vector (or sequence) of keys.
yep
That is one of the main differences between Clojure's built-in update
and update-in
, too. update-in
takes a vector (or sequence) of keys, update
takes only a single key
hmm, I have to think how to solve that one
Your function my-update-in2
works for a single key. It does not work for a vector (or sequence) of keys.
idea is to use apply
somewhere
or maybe recursion
I can see how apply
can help if you are trying to implement the & args
part of the problem.
yep, but that is not the problem now
But I do not see how apply
can help if you are trying to implement the part of handling a vector of keys.
Recursion or a loop sounds more promising to me.
BRB dinnner and I have to take some time to think how this could work
because yesterday you said destruction is almost never needed
and now I need to get the first key
destructuring is never necessary to write a correct Clojure program. It can be a nice convenience in some cases, but you can always write an equivalent Clojure program that does not use destructuring, using functions like first
and rest
or nth
(first [:a :b :c])
;; :a
(rest [:a :b :c])
;; (:b :c)
I would hope that those functions were described early in the book you are using
They work on any vectors or sequences, no matter whether they contain numbers, keywords, other collections, etc.
yep, there are also explained
dinner ready and time to think about this one
am I right I need a anymous function here
I would also put anonymous functions into the category of "often convenient, but not absolutely required", like destructuring.
I do often use them when they are short and thus convenient to use, so I don't have to make up a name for some tiny one-use function.
The only reason I say these things is because you ask if you "need" an anonymous function. When you use that word, it makes me think "there is no other way to write the function I want, other than to use an anonymous function", and that is never true. You can always write a small function with a name and call that instead.
Note: I am not saying that destructuring or anonymous functions are bad. I am only saying they are not needed.
There are some Clojure language constructs that are pretty much needed, or else you cannot write useful programs. E.g. being able to define functions, and call them, is needed for writing practical programs.
and im now lost in parentheses here :
(defn my-update-in [m [ks] f]
(let [up (fn up [m ks f ]
(let [k (first ks)
rest (rest ks)
new_value (f (get m k))
(assoc m k new_value)]))]))
why makes clojuer things so difficult
Does your editor automatically show you the matching parenthesis or bracket for the one that your cursor is next to?
yep
got it after some fiddeling
(defn my-update-in [m [ks] f]
(let [up (fn up [m ks f]
(let [k (first ks)
rest (rest ks)
new_value (f (get m k))]
(assoc m k new_value)))]))
Some fiddling is pretty normal in such situations. Practice makes the fiddling easier.
now time to think where the recursive call wiill be if this a good code
Why did you put brackets around [ks]
in the arguments to my-update-in
?
I thought that was needed
Needed for what?
needed to make it work and tell a user ks needs to be a vector
There are no type declarations on Clojure parameters to tell you they need to be a vector, or a map, or any other kind of thing, the way some languages have.
What Clojure actually does when you write a parameter like that is destructuring. It will expect that second argument to be a vector or sequence, take the first element of that vector or sequence, bind it to the name ks
, ignore the rest of that vector or sequence, and execute the body of the function.
If you write ks
instead of [ks]
there, it will take whatever the second parameter is, a vector, a sequence, a number, whatever, and bind it to ks
, and discard none of that value.
oke, this seems to be complimng
(defn my-update-in [m ks f]
(let [up (fn up [m ks f]
(let [k (first ks)
rest (rest ks)
new_value (f (get m k))]
(assoc m k new_value)))]
(up m ks f)))
I only have to figure out where the recursive call needs to be 😞Looks like a good start to me.
yep me too
Where you now have (assoc m k new_value)
, you need to have (at least) two cases.
do I ?
Warning: rest (rest ks)
using the name rest
there means that in the body of that let
, it will be impossible to call the built-in function rest
because you have re-bound the name rest
to a new value.
If you never do that, then no problem, but if you do try to call the built-in function rest
inside of that let
, it can be very confusing what is going wrong.
oops, what is then a better name for all the other entries in ks
mayeb again ks
?
If the inner let
is only a small amount of code, as I expect it will be, a single letter like r
is probably ok.
ks
looks fine, too, as long as you know it will be all but the first element of the original ks
inside of the let
body.
I will be AFK for a few minutes at least.
oke, no problem
I have called it r
still thinking where I have to put the call to up
Still thinking before the (get m k)
part but then the name is not right anymore
so something like this :
(defn my-update-in [m ks f]
(let [up (fn up [m ks f]
(let [k (first ks)
r (rest ks)]
(assoc m k (up (get m k) r f))))]
(up m ks f)
and I do not work on both cases one still give a error that I have given 7 arguments where 4 are given
and the other one :
(my-update-in p :age inc)
give this :
; Execution error (IllegalArgumentException) at chapter5/my-update-in$up (form-init12940824632450433692.clj:55).
; Don't know how to create ISeq from: clojure.lang.Keyword
Currently you are working on implementing the case without & args
If you are doing that, then stick to it, and never try to call it with 7 args
Pick a single function to call it with, and test it with that, with no extra args.
oke, I did with the p one and it also fails
or is this not a single one : (my-update-in p :age inc)
Earlier I said: "Where you now have `(assoc m k new_value)`, you need to have (at least) two cases." and you answered "Do I?"
Have you written recursive functions before?
yep, in haskell a lot
Have you tried writing a recursive function that did not have two or more cases in its body?
there you had to write a base case when the recursion has to quit and one for the rest
right.
so no, that will cause a infinite loop
the base case is here when ks is empty I think
Same here. You need a base case that does not make a recursive call, and you need a recursive call that does part of the work, but also calls itself recurively on a smaller problem.
The assoc
you have in the inner let
seems like it might be reasonable for a base case.
hmm, so here when r
is empty , have to think what can be done then
When you have only one key left k
which is (first ks)
, you want to do that assoc
call I believe.
The base case is "do the same thing update
would do given that one key"
oke, that way
oke, we need a if
, I believe
An if
would be one way. cond
is another, but if
is good enough for here.
maybe if (== (count r) 1)
???
Do you want the base case to be when r
has 1 key left in it?
if (== (count first) 1)`
Earlier you suggested "the base case is here when ks is empty I think"
if (empty? r)
That seems to me to match the condition "`k` is the last key of the original input sequence, and there are no more"
Looks reasonable to me. Even as written, that should hopefully work if you give a sequence of one key as ks
argument.
am I here right
(defn my-update-in [m ks f]
(let [up (fn up [m ks f]
(let [k (first ks)
r (rest ks)]
(if (empty? r)
(assoc m k (up (get m k) r f))
(assoc m k (apply (get m k) r f))
)))]
(up m ks f)))
I was just about to suggest leaving out & args
again 🙂
The else case of your if
is not recursive.
The then case is recursive, when it should be the base case.
moment, I have to switch them ?
You tell me. In what condition should you make a recursive call, and which one should you NOT make a recursive call?
oke
I have now this :
(defn my-update-in [m ks f]
(let [up (fn up [m ks f]
(let [k (first ks)
r (rest ks)]
(if (empty? r)
(assoc m k (up (get m k) r f))
(assoc m k (apply (get m k) f))
)))]
(up m ks f)))
(my-update-in p :age inc)
; Execution error (IllegalArgumentException) at chapter5/my-update-in$up (form-init12940824632450433692.clj:55).
; Don't know how to create ISeq from: clojure.lang.Keyword
clj꞉chapter5꞉>
You have the recursive call when (empty? r)
is true. I don't think that is correct. There is no reason to keep going with more keys, is there?
when I do [my-update-in p [:age] inc)
I get a stack overflow
here still the same IlligalArgumentException
(defn my-update-in [m ks f]
(let [up (fn up [m ks f]
(let [k (first ks)
r (rest ks)]
(if (empty? r)
(assoc m k (apply f (get m k)))
(assoc m k (up (get m k) r f))
)))]
(up m ks f)))
(my-update-in p :age inc)
; Execution error (IllegalArgumentException) at chapter5/my-update-in$up (form-init12940824632450433692.clj:57).
; Don't know how to create ISeq from: clojure.lang.Keyword
got the feelimg im very close but I oversee something
I don't know your current definition of p
(def p {:name "James" :age 26})
be back in 10 - 15 min. Going for a walk to get a fresh head
What should be the second argument to my-update-in
?
a vector ?
but also then I see that annoying error
a vector or a sequence is what update-in
is supposed to take, not a single key.
(my-update-in p [:age] inc)
You are trying to write update-in
, so you should test it like update-in
??
I got these examples from the page of update-in
Your current goal, if I understand it, is to write a function that works like update-in
. update-in
would give an error if you gave it a single key, not a vector or sequence of keys as the second parameter. So don't test your function in a way that update-in
cannot work.
Which example page of update-in
?
Show me an example page of update-in
calling it like this: (my-update-in p :age inc)
and I will show you a page with a mistake.
this page(https://clojuredocs.org/clojure.core/update-in) but also when I change it to (my-update-in p [:age] inc)
I see this error :
; Execution error (IllegalArgumentException) at chapter5/my-update-in$up (form-init12940824632450433692.clj:57).
; Don't know how to create ISeq from: clojure.lang.Keyword
Every example on that page has a vector of keys that I can see.
oke, but why if I do that I still see the argumentError
maybe because we do not use &args
I don't think & args
can cause that error.
Playing a board game at the moment, so dividing my attention and may be slow here.
oke
we can discuss this later if you have more time
but I see that it chrashing on the (empty? .._)
line
and I do not make any difference if I use r
or k
here
I don't see why it would crash on that line: (empty? (rest [:a]))
returns true
as I would expect. As long as you put r
there, not k
hmm, here it chrashes
(defn my-update-in [m ks f]
(let [up (fn up [m ks f]
(let [k (first ks)
r (rest ks)]
(if (empty? r)
(assoc m k (apply f (get m k)))
(assoc m k (up (get m k) r f)))))]
(up m ks f)))
Take out the apply
. We are not doing the & args
version yet.
This function call gives the same error, and is the reason you are getting the exception: (apply inc (get p :age))
yes, it working 🎉
so now to make ti work with & args ?
Before that, have you tested it with a sequence of multiple keys?
nope
I would recommend testing to see if that case works before & args
it seems to work
(defn my-update-in [m ks f ]
(let [up (fn up [m ks f ]
(let [k (first ks)
r (rest ks)]
(if (empty? r)
(assoc m k (f (get m k )))
(assoc m k (up (get m k) r f )))))]
(up m ks f )))
(my-update-in p [:age] inc)
answer : {:name "James", :age 27}
That does not test it with a sequence of 2 or more keys.
You are still testing the case with a sequence of one key, so the recursive case is not being exercised at all.
(def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}})
(update-in m [:1] assoc :value 1 :active true)
answer : {:1 {:value 1, :active true}, :2 {:value 0, :active false}}
which is also well
satisfied ?
I am
2 days struggeling and both cases solved 🎉
if you do not have feedback then I would thank you for a lot of patience with me
ennjoy the weekend and your family
no further feedback 🙂. May you also enjoy your weekend.
The last case you showed still has a vector of only 1 key, so not testing recursion, though 🙂
hmm, then I have to look for a example for that case
or make one up
maybe this one :
(def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}, :3 {:value 0, :active false}})
(update-in m [:1 :3] assoc :value 1 :active true)
does not give the right answer 😞
also not (update-in m [:[1 ][:3]] assoc :value 1 :active true)
or do you more like this :
(def player1 {:name "Player 1" :attribs {:str 10 :int 11 :wis 9}})
(update-in player1 [:attribs :str] inc)
;; {:name "Player 1", :attribs {:str 11, :int 11, :wis 9}}
where a nested one is done
that one works 🎉
time to sleep here. Again many mny thanks for all the patience with me
a lot to learn how to approach "complex" problems like this
The example with player1
looks like a good test that actually exercises the recursive code.
thanks, it worked also
I get the same answer as the page said
then tomorrow or Monday this page on the menu : https://www.braveclojure.com/read-and-eval/#Summary
that last call needs to be outside the [] binding block
the syntax of let is (let [binding value ... ...] body)
- it's usually a logic error not to provide a body, and it's a compilation error to have a binding without a value (or visa versa)
When first learning, I would recommend avoiding the use of destructuring, until and unless you get a version of a function working without it.
Destructuring can be useful, but it is never necessary.
hmm
you mean like this :
(defn my-update-in [m ks f & args]
(let [[k & ks] ks]
(assoc m k (apply f (get m ks) args))))
(my-update-in p [:1] assoc :name "James" :age 35)
that does this :
{:name "James", :age 26, :1 {:name "James", :age 35}}
and not updating the value
oke
hmm, still no luck
(defn my-update-in [m ks f & args]
(assoc m ks (apply f (get m ks) args)))
(my-update-in p [:0] assoc :name "James" :age 35)
gives this :
{:name "James", :age 26, [:0] {:name "James", :age 35}}
maybe the apply
is wrong here
Im not getting what you want to achieve there. Update-in work with nested maps. And ks is supposed to be a list a key of your map. What do you want to specify with :1 ?
but I do not see any better one
It is almost always possible to take a Clojure function and evaluate it step by step in a REPL session.
Do you know which sub-expression of your my-update-in
above must be evaluated first?
I would say get m ks
yes, good.
And what parameters it should be passed in your example call, and what value it will return?
(If you are not sure, that is where the REPL can be handy)
i think the old value is taken where then the function is applied to
It isn't clear to me what the value of p
is in your call above
sorry, I forget to paste that
(def p {:name "James" :age 26})
we solved that one earlier but I try to make it work that it also worked with (def users [{:name "James" :age 26} {:name "John" :age 43}])
So what does (get m ks)
return?
in the example of p it will return 26
Do you prefer to try to figure out why your current function is behaving like it is? Or do you prefer to start with the input/output behavior of the function you want to write, and try to write that?
Now, try eval'ing this in a REPL: (get p [:0]
and see what it returns.
I think it schould be (get p p: [:0])
that returns nil
so not good
Does it make sense why it returns nil?
yep, I think there is no key named [:0]
correct.
So we can keep looking at what happens with your current function, but maybe you might prefer starting with explaining what function behavior you are hoping to write, because I don't know what that is yet.
You say you want a function that takes a vector of maps like this: (def users [{:name "James" :age 26} {:name "John" :age 43}])
and does something with it, but I'm not sure what you want the behavior to be.
I was hoping to get first a record from a map
so in this example {:name "James" :age 26}
So in Clojure terms, that would be getting the first element from a vector or sequence.
and then I schould find a way to update what I want to update
The value of users
is not a map, but a vector of two elements (each of those elements is a map)
yep, or the second if I want to update the second entry
So try to explain what the parameters of the function you want are, and see if you can give one or two examples of what you want the return value to be for those example inputs, along with a sentence explaining what the function ought to do.
oke, in the example of p. Lets say I want to update the age to 45
Right ?
then m is still p so {:name "James" :age 26}
So p
is a single Clojure map, right, meaning this one: (def p {:name "James" :age 26})
yep
I work from that example first
later we can do more entries
So you wrote my-update-in
earlier that could take m
, a key k
, and a function f
, and do inc
or add-ten
, or whatever function you want, to the current value associated with that key.
That was working.
So now you are saying you want a function that can take a vector of maps, and do something with that.
yep
My first comment would be: you could write a single function that does both, but maybe given that the first argument is a map in one case, but a vector of maps in the other, maybe a different function might be better.
oke
to be sure we are on the same page
i.e. try writing a function that only works if the first argument is a vector of maps, without trying to serve both purposes.
I want to end at a function that can do this :
(def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}})
(update-in m [:1] assoc :value 1 :active true)
outcome :
{:1 {:value 1, :active true}, :2 {:value 0, :active false}}
Once you can see both functions on their own, and get them working, then maybe go back and see if it makes sense to try to write some combination of them that can do both behaviors. But I suspect it will only be more confusing to try to write that combined-behavior function first.
oke, no problem to take one of more steps back
So in this example call (update-in m [:1] assoc :value 1 :active true)
you have a vector containing :1
. Do you want this proposed update-in
function to be able to take any number of keys in that vector, 1 or more? Or do you want it to only work for 1 element in that vector?
If you only want it to work for 1, then why put it in a vector?
maybe better to make it work with 1 element first
and then look what needs to be changed for multiple entries in the vector
I guess perhaps from the name update-in
, you might be thinking along the lines of how get-in
works in Clojure?
Are you familiar with get-in
?
yep, that one is explained in this chapter as Whereas the function
get-in` lets you look up values in nested maps, `
So if your update-in
is intended to be similar to get-in
, in that it can take a vector of keys, and update a value in a nested map, then it makes sense that it should be a vector. In fact, your update-in
would likely want to use get-in
to get the current value.
moment
it does not work as expected :
(def m {:1 {:value 0, :active false}, :2 {:value 0, :active false}})
(get-in m [:1][:active] )
gives
{:value 0, :active false}
I expect to see only falseHow many keys to you give to get-in
/
?
Oh, I see what you did. That is not how you give a sequence of multiple keys to get-in
. Try this: (get-in m [:1 :active])
1 sequence of keys, not multiple separate sequences of keys.
yep, that works
get-in
takes an optional 3rd parameter, that if you give one, and if the sequence of keys you give are not found in the collection, it returns the 3rd parameter to indicate "not found", instead of nil
In this call: (get-in m [:1][:active])
there is a key :1
, so the 3rd parameter is not used.
yep, I see it : (get-in m [:3 :active] "not-found")
gives not found
yep. as it is documented to do.
(once the documentation makes sense, that is 🙂
yep, and I tried to see if I really understand things
experimentation at the REPL with different variations of an idea are definitely good ways to test your understanding.
yep, I will , can we talk tomorrow about this further
its late here, 22:36
sure. I will warn you that I expect update-in
will be a bit more code to write than my-update
you wrote earlier, but doable with patience.
and I will experiment if I can make it work on a different keyword, so on value
and active
It is definitely a good idea to have a good understanding of what Clojure built-in functions like get
and get-in
do, especially when relying on them to write your own functions.
and then try to adapt it to make it also work on the different entries so the keyword and the number of entries (1 or 2)
so first understand that
and then look how I could change a value and make a new map
thanks for the lessons
you are the first one which do not give a answer but let me think about a solution
for now GN
It usually takes longer to ask questions that let the learner think about a solution :-)
My hope is that you will learn questions to ask yourself, and habits of thought, that let you more often find the answers yourself.
and got the code where the number and the keyword is a variable
(defn get-on-keyword [m keyword number]
(get-in m [number keyword] "not-found"))
and now really sleep
Maybe a idea to try now t change the get-in
into update-in
? after some sleep naturlly