Clojure's core.typed vs Haskell
adambard.com
adambard.com
Still, I think core.typed does pretty damn well for being a standalone library.
Nah, Coq, Agda, Idris and any dependently typed language have Haskell beat -- their type systems are designed to be just as expressive as their value language. Haskell is certainly moving in this direction, especially with modern extensions. The issue is of course type inference breaks down in the face of these extensions, and Haskell is trying to maintain its powerful type inference as best it can. Certain combinations of extensions already force type annotations.
> Still, I think core.typed does pretty damn well for being a standalone library.
This is true, and I think the comparison to Haskell actually hurts the greater point you're trying to make. Haskell has full static types at its disposal, and comparing them to the optional typing of Clojure will always leave something wanting -- why draw that comparison when competing with Haskell is not the intention of the library?
That may be true, but it comes at a big cost: inference and decidability. Haskell's type system is designed to very carefully butt up against the limits of these features. Once you go full-spectrum dependent types, you lose all that.
So with that said, you're absolutely right.
I'm sure I'll take a look at it again sometime, but I'd really love some kind of intro that helped me to understand why it was worth the time investment to get to know it.
I don't know if I would phrase it that way, but there's a more important slight of hand going on here and I think chongli was right in spirit. Haskell takes care of (most) type level things for you with inference. Coq and Agda allow you to give very precise types to things, but those very precise types involve values that are not automatically inferred for you. It's certainly not the case that you can write the same annotation-free function in Coq that you would have written in Haskell and have a very precise type inferred for you.
I just knew someone was going to correct me on that statement, hence my "mainstream-ish" qualification.
> why draw that comparison when competing with Haskell is not the intention of the library?
I've got an unhealthy obsession with syntax, and I wanted to have a reference for people to see how things look in a "real" typed language. But, while I'm here, here's a bit I just wrote on /r/haskell (someone put this link there, but of course the haskellers were unimpressed) in defense of the library:
---
Developing in Clojure tends to be a bit of an organic process, thanks to the deep REPL integration in many tools. You can evaluate arbitrary bits of your code as you go, swap things out, tweak whatever you like, and through a more-or-less exploratory process end up with a working bit of code. It's very freeing and very efficient, but if you've ever used a dynamic language for a large project, you know that this tends to create issues refactoring later unless every component is attached to a unit test. The power of core.typed is to let you, after the fact, lock down those function signatures and create what amounts to an automatic test suite.
Though you can send arbitrary code blocks from vim using vim-slime.
When I first began developing Haskell, coming from Clojure, these issues drove me crazy. Nowadays I don't miss them too much and doubt that they're really such good features to begin with...
But it's decidedly false to claim that GHCi is as flexible as Clojure's repl. Nowadays, Clojure's repl would make me anxious. It reminds me a bit of people doing live code edits on a production server. You can't ever be quite sure what you get.
(Serious questions, though even if the answer is yes I can't really see it drawing me away from scala)
This gives you a pragmatic equivalent to no-check, but is almost never used in practice because it turns out to be unnecessary.
[1] http://ghc.haskell.org/trac/ghc/wiki/DeferErrorsToRuntime
Edit: Just found Seqable. Looking into it now. This link helped me a lot. https://github.com/clojure/core.typed/wiki/Types
(ann my-keys (All [a] [(t/Map a Any) -> (t/Coll a)])
Isn't the reason why you need to do it because you're importing a non-typed symbol? Wouldn't the only situation where you'd need to do that in Haskell be at FFI?
(and a nitpick: `putStrLn $ show` can be replaced with a simple `print` call)
http://www.haskell.org/ghc/docs/7.6.2/html/libraries/base/Un...
As the word "unsafe" implies, these Haskell primitives forego type safety in addition to type correctness. That means you can get segfaults and other undefined behavior at runtime. Such a type error on the JVM will simply produce an exception at runtime.
It almost never comes up because it turns out to be virtually useless, but that's a story for another time.
That's debatable, however Data.Dynamic is built on top of Data.Typeable, which provides a lower level runtime type safety facility. I think we can both agree Typable has lots of interesting uses.
This is with about 15 minutes of looking at core.typed. Isn't this because the type Interger is actually java.lang.Integer, but (type 1000) is java.lang.Long?
Also, AnyInteger isn't that permissive. It's defined as (U Integer Long clojure.lang.BigInt BigInteger Short Byte). The big difference would be that Haskell's Int is bounded so AnyInteger is more like Haskell's Integer.
divBy x y = y `mod` x /= 0
divBy3or5 x = divBy 3 x || divBy 5 x
euler1 n = sum [x | x <- [0..n], divBy3or5 x]
main = print $ euler1 1000
Personally, I'd switch out lines 2 and 3 to: euler1 n = sum [x | x <- [0..n], divBy 3 x, divBy 5 x]
Compared with the Clojure (correct me if I'm wrong): (defn euler1 [n] (reduce + (filter (fn [x] (or (div-by 3 x) (div-by 5 x)))) (range n)))
Edit: Note - Clojure code doesn't fit into a HN one-liner. (defn euler1 [n] (reduce + (filter #(or (div-by 3 %) (div-by 5 %)))) (range n)))
Or if you're into comprehensions: (defn euler1 [n] (reduce + (for [x (range n) :when (or (div-by 3 x) (div-by 5 x))] x))) (defn div-by [x y] (== 0 ))(mod y x)
a typo or a Clojure feature?A feature, in my opinion.
Well, Clojure's a different language so it doesn't matter as much. If Clojure had enforced purity and pervasive laziness (a la Haskell) it'd be a real pain to use monads without polymorphic operators for them.
[1]: http://math.andrej.com/eff/
[2]: http://lambda-the-ultimate.org/node/4786
[3]: http://erights.org/elib/capability/ode/ode-capabilities.html
1 line of python.
print sum(filter(lambda x: (x % 3 == 0) or (x % 5 == 0), range(1, 1000)))
clojure
(apply + (filter #(or (= 0(mod % 3)) (= 0(mod % 5))) (range 1 1000)))
sum [x | x <- [1..1000], mod x 3 == 0, mod x 5 == 0]
But as you say, that wasn't the point of the article....so you object to his solutions because you don't care about the point of the article, which is what forces him into those specific solutions.
Well then I'm afraid the article has nothing to offer for you.
print sum(x if x % 3 == 0 or x % 5 == 0 else 0 for x in range(1, 1000))