This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-07-28
Channels
- # aleph (1)
- # arachne (4)
- # beginners (13)
- # boot (18)
- # clara (7)
- # cljs-dev (156)
- # cljsrn (278)
- # clojure (163)
- # clojure-conj (5)
- # clojure-dev (1)
- # clojure-losangeles (1)
- # clojure-poland (2)
- # clojure-sg (1)
- # clojure-spec (15)
- # clojure-uk (17)
- # clojurescript (275)
- # data-science (5)
- # datomic (23)
- # emacs (10)
- # leiningen (1)
- # lumo (16)
- # off-topic (98)
- # onyx (10)
- # parinfer (83)
- # re-frame (18)
- # reagent (47)
- # remote-jobs (1)
- # ring (1)
- # ring-swagger (5)
- # rum (6)
- # specter (8)
- # vim (5)
so I have been studying racket, and really like the language, including it's builtin match (more than clojure's match), it's macro system, ...
@qqq Hows the immutable data and succession of states story in Racket
@tbaldridge : I think Clojure can learn alot from typed-racket and syntax-parse.
@qqq I find spec to be better than both, honestly.
something like spec (or racket contracts) is much more flexible and powerful than types.
And declarative macro syntax will break down at some point. Spec is an excellent answer for macro input validation as well.
they seem like all totally different things to me
and so i'd have trouble considering any of them "better", personally
i also don't have any experience with any of them... so there's that, lol
I also find comparing them does a disservice to both. They are not directly comparable.
So typed racket is closest to typed Clojure. Racket also has a contract system that has similarities to spec.
So I'm comparing them in the same way I'd compare any type system to spec. Spec is more flexible as you have the full power of the language at hand.
As far as define-syntax bit goes. It works well enough for simple macros that are simple expansion patterns, but more advanced macros will require an escape hatch. With these more advanced macros (like you often need for DSLs) you often end up with a parse phase (which spec handles very well) and an emit phase which is just the creation of some datastructures.
Both typed Clojure and define-syntax for Clojure have been tried several times, but both end up being fairly limiting.
I think Typed Clojure actually has some #lang like feature in it, though I have no idea if it does anything like what Racket does
for type checking in general, if the user is asked to provide a type for each function, is that generally enough to infer all the remaining types ?
(if true "a" :b)
things are gonna get weird even on non user-defined functions. What's the type of this function?
clojure will allow things that aren't part of the rigidity required by typed languages, AFAIK
or what's the type of this?
(fn [x] (if (string? x) (keyword x) (str x)))
That's what makes transducers almost impossible to type ^^. The type of the return value of a transducer can depend on the input value, or previous values in the accumulator
@qqq you're gonna run into a problem as well. The closing keynote at the seattle clojure/west was about someone doing gradual typing from the racket world and they called it fundamentally broken. it would be worth a watch
but basically anytime you leave a rigid world of types and come back all you know about the input is that its object or something similar and that throws off what you can infer going forward
@tbaldridge: dependent types for Clojure? Wonder if that’s even possible. (I’m reading https://www.manning.com/books/type-driven-development-with-idris)
I think that with spec you can specify what conditions you expect the result to be in relation to its input.
@mobileink and of course since you have an entire language behind you (and not a DSL) you can really do anything with spec.
There was a funny talk I saw once by the author of Idris, where he's write a fn type and then hit a Emacs macro that would implement the function given the type
but at that point, aren't you just writing in a dynamic language (a type DSL)?
you are only leveraging the feedback the compiler is giving you to add just enough code to satisfy it
but if you put that much info in the types you're just moving the runtime into the compiler
but if you change the function signatures, your code won’t compile, while with dynamic language, it won’t flinch until something goes wrong at runtime
still the possibility of using spec for something approximating real dependent types seems pretty cool
It doesn't even need to be 'terrible'.
"with dynamic language, it won’t flinch until something goes wrong at runtime" I think a lot of this is mitigated by spec making much easier doing generative testing on fns
that is still an additional effort tho… I prefer the computer to do as much work as possible for me.
(s/def ::config (s/*
(s/cat :prop string?
:val (s/alt :s string? :b boolean?))))
(s/conform ::config ["-server" "foo" "-verbose" true "-user" "joe"])
s/*
…. and this coming from a community that is very vocal about scala’s “obscure” syntax
that's standard regex syntax
you can always write your own macro
(s/fdef with-new-notes
:args (s/cat :melody ::melody
:new-notes (s/coll-of ::note :kind vector?))
:ret ::melody
:fn (s/and #(= (-> % :args :new-notes count) (note-count (-> :ret % :notes)))
#(= (-> % :args :new-notes) (remove rest? (-> :ret % :notes)))))
I find it more readable if I have something like fun withNewNotes(melody: Melody, newNotes: List<Melody>): Melody
but that type isn't doing the same thing
you're comparing apples and oranges though
your type definition doesn't compare the return value to the input value
you can put that inside your logic, or better yet, use dependent types if the type system supports it….
That's an odd thing to say in this context - then you are right back to runtime checking which seems to be what you just don't want to deal with.
so show me the same with dependant types
my point was: spec is too verbose and cryptic and I find it hard to read code that uses psec
and my point is you're not comparing like things
spec is a much more powerful than java types, and with that power comes a certain level of verbosity
heh, people could even write a DSL for spec that made spec into a Java types-esque thing
but that's what you used
nothing about your function type is more advanced than java
app : Vect n a -> Vect m a -> Vect (n + m) a
app Nil ys = ys
app (x :: xs) ys = x :: app xs ys
i agree spec syntax takes some getting used to, but how is that different than any other?
I agree, I find that definition of app completely unreadable
and I find idris unreadable because it's all just whitespace and symbols
To me, the main reason why I don't use a statically typed language is that the moment you touch the outside world, you're untyped. The web isn't statically typed, and trying to force it to be so is just asking for a bunch of pain.
So the moment you hook a program up to the web, a lot of type guarantees go out the window.
So for me, I prefer spec + generative testing.
yeah, I found that to be an issue too when I was just starting to experiment with scala and Kotlin. But I think it made me a better developer because it made me deal with those things up front and isolate the business domain from the outside world. I like how that has turned out and even use the same approach with dynamic languages. So on the interface with the outside world, I format the data in the format the rest of my application expects it to be. It also made me document those expectations up front by encoding them in types.
I used to have a hard time with typed languages but got over it once I decided to slow down and be more delibrate
ironically enough, Rich’s talk about Hammock time
was one of those things that made me embrace type systems.
heh, I'm the opposite.
I find type systems to get in the way and keep me from actually writing the code I'm trying to implement
@roberto on that subject https://gist.github.com/halgari/f431b2d1094e4ec1e933969969489854
Your point about nominal vs structural is really spot on to me. It is a major reason why HM like systems (ML, F#, Haskell) always make me think - "This stuff just doesn't capture the semantics of what is going on"
some of your concerns are addressed by more advanced type systems. But yes, in Java I have the same issues you described.
@tbaldridge re: touching outside world, yeah, after a romance with the heavy-duty typed stuff i've come back to "really great, except when it isn't". still, Idris has a very interesting take on state, concurrency, etc. mind-expanding at the least but i'm not yet sure i would ever use it in anger.
Could be one of those things where it's very powerful inside a scope in which you have total control, but you gotta bound it with more versatile tools as soon as you start interacting with external systems.
Your point about nominal vs structural is really spot on to me. It is a major reason why HM like systems (ML, F#, Haskell) always make me think - "This stuff just doesn't capture the semantics of what is going on"