This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-04-12
Channels
- # bangalore-clj (4)
- # beginners (77)
- # boot (71)
- # cider (10)
- # clara (1)
- # cljs-dev (52)
- # cljsjs (28)
- # cljsrn (1)
- # clojure (390)
- # clojure-dev (5)
- # clojure-india (1)
- # clojure-italy (5)
- # clojure-nl (24)
- # clojure-poland (4)
- # clojure-russia (123)
- # clojure-spec (71)
- # clojure-taiwan (2)
- # clojure-uk (8)
- # clojurescript (236)
- # core-matrix (6)
- # cursive (19)
- # datomic (16)
- # defnpodcast (2)
- # editors (1)
- # emacs (36)
- # garden (2)
- # hoplon (5)
- # jobs (1)
- # jobs-discuss (10)
- # juxt (47)
- # luminus (4)
- # lumo (6)
- # off-topic (207)
- # om (1)
- # onyx (20)
- # pedestal (40)
- # perun (2)
- # re-frame (8)
- # reagent (48)
- # ring (2)
- # ring-swagger (2)
- # specter (13)
- # unrepl (89)
- # vim (6)
Thanks for the link @drewverlee, leanpub is just too slow to be trusted from where I am, I'll pass this one š
using ragetime migrations
Want to create a concurrent index , How to ?
CREATE INDEX CONCURRENTLY sales_quantity_index ON sales_table (quantity);
perhaps a dumb question... any thoughts on why
(defn nums*
([] (nums* 0))
([n] (cons n (lazy-seq (nums* (inc n))))))
works but
(defn nums*
([] (nums* 0))
([n] (conj [n] (lazy-seq (nums* (inc n))))))
throws a stack overflow error?when I do (take 5 (nums*))
?
conj on a vector is eager
thereās no point in that call where lazy-seq can say āOK, I got a collection, I can stop nowā - it keeps calling nums* and not getting result because nums* recurs
so you blow stack
interesting, but cons is lazy?
okay... good to know. I was under the impression that conj
was preferred ... perhaps for no reason
cons works nicer with lazy-seqs - conj needs to evaluate the collection arg in order to know what to do
if the colleciton arg is then a recusion - well down we go into a recursion
cons
doesnāt change the laziness/realizedness of the seq arg
conj
preserves the type of the collection arg
I hope that clarifies and is not simply pedantic š
so is it more of a conj/cons
thing or a vec/list
thing?
cons
will always give you a seq where the head is a cons cell (or a list, where the seq is null)
and the rest is TBD?
conj
on a vec appends; conj
on a list prepends; it means add a value to the given collection in waves hands the best way you know how
yayyy
that's fine, that's the level of abstraction I'm at
When would you dispatch based on a function rather then a recorded piece of data. That is, when does it make sense to use a protocol vs multimethod? It seems like you could take the mm function out and use it to produce the record.
I suppose its a question of weather it helps to capture that new type/protocol?
Right i guess the reasons to use protocals are because their faster and possible the communicate something to the user. I suppose in general though i would just use a multimethod so i could avoid having to create a new protocal? Is that the right way to think about it?
@drewverlee Protocols dispatch on the type of the first argument. They also group related functions together. So they're useful when you want to add functionality to a type. They work well with records, since records are one way of creating types in Clojure.
I reach for a protocol when I have a coherent abstraction, particularly when the production impl has meaningful side effects
Interesting those blog posts about mapping design patterns with Clojure, though I think they might be more confusing to me than anything. I mean the book is called "Design Patterns: Elements of Reusable Object-Oriented Software" They don't really make sense without OOP
Most of the patterns in GoF anyways, what makes them so hard, is all the ceremony of wrapping everything in classes and objects. These constructs have a lot of constraint, so trivial things in FP appear much harder, though they are trivial in practice, how to set them up in code using classes and objects becomes complicated.
@didibus The use for those blogs posts is very specific. Primary goals are meant to teach me more about FP, Clojure, OO. Secondary goal is to teach my team mates who really learned a lot from the GoF how those principles relate to FP. I have to bridge the gap with more then handwaving.
Ya, those are good goals. I'm worried they might confuse a newcomer more than anything though.
newcomer to clojure?
clojure isnāt untyped, itās itās runtime dispatched with a unitype - thereās a difference
forth for example is untyped
āIn typed lambda calculus, functions can be applied only if they are capable of accepting the given inputās ātypeā of data.ā - clojure does this, at runtime
but sorry, I think thatās a tangent that isnāt especially useful in this conversation
Hum, I'm not sure that's true that this is how the untyped vs typed lambdas apply. What does it mean can only be applied? I think it means you constrain yourself from doing so. It is a conscious thing. In Clojure, you don't, you allow it, but it garbage comes in, garbage will come out
I appreciate the insight @noisesmith.
if the object that receives the method doesnāt implement it, you get a stack trace - the vm enforces the types based on parametric polymorphism, which is an object oriented flavor of typing
Well, ok, as I was writing this, I saw your point. At runtime, it'll throw a type error, so it won't always allow it and see what happens. I guess that does make Clojure a weird hybrid like you said.
whereas if you hand a forth word the stack, and it decides to read an int, it will treat the top 16 bits as a signed integer, regardless of who put those bytes there and what their original size was
(eg they could be two bytes out of an eight byte float, who knows)
Ya, I normally call that distinction strong vs weak typing. And I consider clojure dynamic strong. I was using untyped to refer to dynamic vs static in this case.
And, back to topic, I was making that distinction because I've found people new to it get confused that often times, you don't create a type for your data, but just use standard data structures with special shapes.
So, for bridge, like @drewverlee has in his blog post, he just modeled it as {:shape :triangle :color :red}
right - to me the biggest difference between OO and FP isnāt what you can/canāt do, but which kinds of operations are considered worth your time
eg. - how often should you implement new data types? how visible should your data be by default? how strong is the connection between data and the code that uses it?
I've noticed, even in strongly typed FP, people find this surprising. They would create an algeabric data type to model the above data. So I think that makes Clojure unique in this way.
other lisps come close, but they have a poverty of good data types
(or at least ones that are convenient to use and ubiquitous)
Ya, Clojure has great data structures, which makes this awesome. I think of it as structural vs nominal types. In Clojure, you create structures, and things that work over them. It doesn't matter the name of the structure, as long as it has the structure the function needs. And generally, we restrict this a little, so structures are either sequential or associative. So we'll have types of structures which will be checked at runtime, but appart from that, if the structure is what the function needs, it will work.
You don't have to do this, you can create data types, use records for example. Those are useful when you need identity. And if you want to create a new category of structure, use deftype. At least, this is how I see it.
> eg. - how often should you implement new data types? how visible should your data be by default? how strong is the connection between data and the code that uses it? These are exactly the sorts of questions iām wresting with as i work through these GoF examples. Not in understanding the patterns, but thinking about how they would translate to clojure. Part of the stress is that their the explanations are so lengthy, that when iām done implementing in them in clojure and have 7 lines of code. I feel like i messed up somewhere, or iām missing the point.
⦠and then I need to refactor something and suddenly Iām stuck trying to rewrite code where I donāt have any idea what the shape of the data was it was written for unless I actually go and snoop on the running application due to the combination of generic sequence and lookup operations that accept all kinds of inputs and asynchronous and threaded operations that dissociate the function from the entity that created the data that it acts on /gripe
So, if you don't have a name for your type, you need a multimethod, so you can dispatch on the structural characteristics. If you have a name, you can use protocols.
@noisesmith Haha, yep, that's why Rich is making Spec š
and then I use plumatic/schema to enforce some data constraints (for documentation reasons if nothing else) and then other people edit the code that generates the data but never update the schemas so now we have stack traces and log messages complaining about the data flowing through but the app worksā¦
@drewverlee I think for you its probably a good learning exercise. Would be for me. But ya, I'd trust your judgement, those patterns are often harder to understand than what they actually provide. And that's mostly because they are really tricks around OOP constraints.
Would be nice to get more guarantee for that problem. With spec, I guess, if you run the generative tests you'd see that you forgot to update the spec.
yeah- itās not even clojure specific, itās a consequence of using vanilla data structures - a tradeoff I opt into by using a lispy language
oh yeah, tests are a good idea too haha
> itās a consequence of using vanilla data structure what is?
the general mess I get into with refactors
the code doesnāt tell me much about the structure that was passing through - all that I know is that some very generic data manipulations are being applied
of course you can end up with messy code in any language
@drewverlee What I wanted to say, with some of my coworkers I've introduced to Clojure. I often actually have to start by explaining to them what OOP is in reality. I tell them not to confuse the technique of modeling problems as things, and the language constructs of Java, C++, etc. The GoF patterns are often patterns for the constructs. Not modeling techniques. You can have groups of related data in Clojure, you can do that with records. You can also have groups of related functionality, you can do that with protocols. Namespaces can group data and functionality together. Nothing stops you from modeling things this way. But the construct you'll use to implement the model are just different.
> The GoF patterns are often patterns for the constructs. Not modeling techniques. thats insightful! Iām willing to bet the authors were aware of the tradeoffs. So far what i have read has been very well thought out. I doubt ill read the thing cover to cover though. Just pick on a few and demonstrate how the concepts flow or dont to clojure. > What I wanted to say, with some of my coworkers Iāve introduced to Clojure. I often actually have to start by explaining to them what OOP is in reality. This is sort of what iām learning how to do. I mean, i would more accurantly say iām comparing Java to Clojure (i bet im the first one!). Using the GoF book in that regard probably has diminishing returns, as java has changed a lot.
GoF is a good book. But its a book about how can you model things which do not work well with an OOP model, while still using OOP constructs.
OOP is great if you need to model a group of things and there relationships, as long as those things are real objects in the real world. Like a Family. Mother, Father, Son, Daughter, Uncle. This is a great use case for using an object model. Now, if you want to model a rendering system, you need to shoe horn it inside an OOP model, because there are no objects. There's a big complicated piece of code that can draw, and a language that can describe graphics. In OOP, you need something like bridge to not have it be too bastardized as objects and relations. But in Clojure, you can write a draw function which takes a declarative graphics DSL. Done.
That's why I think you'll find your Clojure alternatives are always very small and simple.
@didibus interesting. michaeldrogalis has a talk on information models, where i think you can get back some of the relationships your talking about: https://www.youtube.com/watch?v=kP8wImz-x4w It seemed like it was a way to bring back types, but maybe i was missing the point. Iām not saying thats bad, itās awesome that so much is optional in clojure.
my favorite part of that talk is in the Q&A when i ask a nonsense question related to another talk because my brain was melted.