Hacker News new | past | comments | ask | show | jobs | submit login

Ah, thanks. I think the case of map and filter is simple in that the returned type doesn't vary ever, you always get back a lazy sequence. And if you want vectors back you can use mapv/filterv. But I see how people coming from other languages might expect the default to be maintaining the sequence type.

But more generally lazy sequences (and their prominent/default usage in builtins) seem to make code execution less predictable without delivering big benefits. One of the less successful features in Clojure IMO.




Sure when you have a simple sequence then you can just use mapv or filterv (reduce of course already let’s you control the output type). But try it on a deeply heated structure and it becomes extremely cumbersome. In spectre, it just does what you expect.

Of course, that’s not everything specter can do. I’d say it’s probably the least interesting of specter’s features. Much more interesting is how powerful the path selector system is. For example, you have a bested structure, let’s say a vector of maps and one key of the map is a vector of numbers. In spectre you could get at all of the numbers in all of the maps, take just the odd ones, sort them, reverse and put them back into the various different maps in the vector. That is incredibly hard to do by hand!

Ie: [{:a [1 2 3 4]} {:a [5 6 7]}] => [{:a [7 2 5 4]} {:a [3 6 1]}]

Regarding lazy sequences. I agree that they’re not as useful as perhaps touted. I’m not sure I’d call them failed, but definitely they didn’t turn out quite as useful as maybe was expected. Having said that, they do have their moments where they are super useful. The question is whether they could have been made optional, so you use them only when needed... Also, (map foo (vec whatever)) will still lazily map over whatever even though it’s a vector, so devolving into a lazy sequence isn’t a necessity to enable laziness, but rather it’s just that Clojurescript sequence functions don’t maintain the type. I think Clojure‘s sequence functions should (by default, perhaps with a way to turn on current behaviour instead if there’s a performance or other reason) maintain the input type. Even if internally it works on a lazy seq, it should check the type of input and make sure the output is the same type. conj is generic (works for lots of types) and maintains its input type, map, filter etc could too. This would make them behave more like you would expect coming from another language without getting rid of laziness in any way.

Ideally this would be done without converting to and from lazy sequences internally, but if that’s necessary then a way to turn it off for performance would be good, or a way to fuse multiple operations together (via transducers maybe?). I can see how this idea would add complexity if you want the best performance and perhaps that’s why it was decided to just return lazy sequences and metro the programmer decide what to do. Clojure often does sell itself as a language for professionals and avoids doing things just because it’s easier for beginners. Still...


I can undertsand the appeal of specter but it just seems too much magic to me. Probably I'd reach for meander first, though I haven't really used either. So far I've gotten by fine with the basics plus walk/postwalk, and datalog queries against the DB.


Oh, I mean, I mainly use update-in and assoc-in too. Specter is pretty powerful though. I once wrote CSS-like selectors to work on hiccup using Specter.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: