Fork me on GitHub
#beginners
<
2017-07-05
>
drewverlee02:07:17

I like how the problems on 4clojure are 2x harder then any i have solved in my professional career so far… This one is a puzzler. I keep getting close but then their is some flaw to my plan. Like, the problem is handling the numbers that dont fit. Its easy to keep the full structure by filtering out the bad ones, but the answer doesn’t have the same structure of collections. Or its easy to stop at the last number that doesn’t fit, but then i can’t construct a function that doesn’t return nil for that number and muck up the whole thing. http://www.4clojure.com/problem/112

noisesmith02:07:27

oh yeah, horribilus is right

noisesmith02:07:55

that one took me a long time (I stopped doing 4clojure for a while when I hit it, came back and approached it totally differently later)

gonewest81802:07:25

@vinai I sometimes use spyscope for this especially when debugging. Specifically the #spy/p reader tag is the one that pretty-prints the form that follows. https://github.com/dgrnbrg/spyscope

noisesmith02:07:30

I think one thing that makes the puzzle particularly hard to solve in clojure is that its logic doesn't really respect the structure of the data, which makes us deal with the input in ways that are "weird" compared to our usual facility with data transforms

noisesmith02:07:36

like, a deeper element might cause us to erase elements that are higher, or a higher element might make us remove ones that are deeper... it doesn't really fit our usual patterns very well

drewverlee11:07:08

@noisesmith thanks for the perspective!

noisesmith16:07:06

drewverlee: thanks for reminding me of this problem, it’s a hard one. I ended up deciding I didn’t like my old answer (using an atom for a counter) and I replaced it with what turned out to be: a hand rolled monad pairing a subseq or element with a number representing remaining capacity

noisesmith16:07:26

it doesn’t work with laziness though… I think I might need to turn to something like reify to make that work

drewverlee16:07:12

Hmm yes I also went for an atom, I'll have to take a look at your solution when I finally get something to work

a1313:07:51

> http://www.4clojure.com/problem/112 it looks like I solved it, but pretty hacky, using keywords for returning multiple results

dominicm13:07:56

Seems like something that might be suited to zippers... no idea if they work on infinite sequence

a1314:07:39

no zippers, just a recursive function with 2 arities

dominicm14:07:44

Oh, I didn't read the sum part, I thought it was a nested filter. Not sure if zippers can be told to "remove everything else" I suspect not in a way that's safe lazily, so probably not good.

a1314:07:36

found a bug in my soulution and an absent testcase on 4clojure 🙂

a1314:07:30

fixed 🙂

gonewest81817:07:17

modern-cljs related boot question. Unclear whether to post a bug to the github project, ask here in #beginners, or ask in #boot.

gonewest81817:07:31

in tutorial 16 there’s a note that says, basically, if you do a (merge-env! :source-paths dirs) where dirs contains nonexistent paths, that there should be no error. https://github.com/magomimmo/modern-cljs/blob/master/doc/second-edition/tutorial-16.md#update-buildboot

gonewest81817:07:23

but I’m getting an exception “Exception in thread “Thread-18" java.nio.file.NoSuchFileException: test/clj” where the path test/clj does not exist… ?

gonewest81817:07:39

nevermind - I just opened a ticket in modern-cljs (https://github.com/magomimmo/modern-cljs/issues/429)

magomimmo17:07:47

@gonewest818 I’ll take care of it in a couple of days. Thanks.

matan20:07:35

ever had a test inside a with-test, mysteriously ignored by leiningen even when *load-tests* is true?

drewverlee20:07:55

Super nooby question, but what are the pros and cons of accessing your data only through functions you define? (defn make-person [f-name l-name] {:first-name f-name :last-name}) (def drew (make-person "drew" "verlee")) Now say i want to access my first name. I could do this: (:first-name drew) which is direct but relies i know about the structure of drew. Or i could build a function that does that. (defn get-first-name [person] (:first-name person) and then access it using this getter… (get-first-name drew) ;;=> drew The way i see it, the later is more flexible as it lets you change the structure of the data containing the name. The downside is that you have to build lots of getters, which generally leaves me feeling lke i’m doing something wrong. Possible this is because setters are the real code smell but my mind associates them together.

noisesmith20:07:39

this also prevents things like get-in

noisesmith20:07:04

unless get-in also knows about the structure of course

matan20:07:22

@drewverlee I think you've summed up the pros and cons alright.

noisesmith20:07:02

also note that most of the things that make clojure great depend on not using accessors

matan20:07:21

@drewverlee unlike Java, you're not forced to have a getter for everything under the sun

ghadi20:07:50

great question @drewverlee -- what @noisesmith says about get-in applies to the rest of the standard library too

ghadi20:07:25

see my comment in #clojure at 4:01

drewverlee20:07:50

@ghadi I might be some of the context from what your saying around 4:01. I wasn’t suggesting building a new type. Just making it so that access to the object went through a user defined functions rather then relying on functions that were Data structure specific. I dont see how this would effect the rest of the program. (map get-first-name [person-a person-b]) vs (map :first-name [person-a person-b]) However even as as i write this i feel like the trade off in creating accessor is greater then i originally thought. I mean [person-a person-b] is data, should i make an api for that? Where would it end? So are we suggesting that its worth breaking your code if the data has to change. {:first-name drew :last-name verlee} -> {:names {:first drew :middle alan :last verlee}} which would mean i have to change every place is access the first name via a keyword. e.g (:first-name person) In order to avoid the overhead of creating accessors? In essence keep the data as generic as possible so we can re-use as much of clojure core as possible?

ghadi20:07:00

in clojure the data (generally) is the API

ghadi20:07:29

as you say, the accessors have a high cost of reusability

ghadi20:07:26

if you make an accessor like get-first-name that does something non-obvious with its argument (like assembling/computing a value, etc.) then anything else in the program needs to call that accessor instead of looking at the (immutable) data

ghadi20:07:03

definitely not trying say there's never a use case for something like that

ghadi20:07:49

but i think it's rare. most accessors in java end up exposing object innards as information

ghadi20:07:12

not very common over here in clojure

drewverlee20:07:57

@ghadi so in general, you would recommend accessing data using data? e.g

({:3 "3"} "3") => "3"
([0 1 2 3 4] 3) => 3
(#{1 2 3} 3) => 3

ghadi21:07:39

in general use :first-name instead of making a micro-API (a function) get-first-name

ghadi21:07:55

in general

ghadi21:07:53

some good (old) discussion here from 6 years ago

matan21:07:58

I think it would be more accurate to say the real reason is that since (in clojure) data is immutable, there's no need for a getter.

swizzard21:07:58

it’s also an isomorphism thing

matan21:07:59

That said, if you wish to access only a certain piece of some data, or a transformation of it, you may write a function that derives it for you; not a getter, but mildly reminiscent

swizzard21:07:24

get-in/`update-in` take vectors

swizzard21:07:31

that you can manipulate like regular data structures

swizzard21:07:05

because they are regular data structures