def greater_than(a, b):
return a > b
if __name__ == '__main__':
print(greater_than(5, 4))
print(greater_than([], 4))
Which is a perfectly valid program, but throws a runtime error. However, in Haskell: module Main where
greater_than :: (Ord a) => a -> a -> Bool
greater_than a b = a > b
main = do
print $ greater_than 5 4
print $ greater_than [] 4
I have added a constraint that forces the caller to pass a value that can be compared - and the compiler will throw an error if I don't do that.Of course this won't get rid of every problem programmers face, but it helps.
greater_than = (>)
...sorry. The way you wrote it is better for illustrating your point to non-Haskellers, it just felt dirty!Yes, type errors. The problem is you have a drastically limited idea of what a type error is.
>The type system, for example, does not help you when you have five Ints and you use the wrong one for an index and the output of the procedure is thereby completely messed up at runtime.
Yes it does, you are choosing not to use the type system. If they are not five Ints but five specific things, then you should have five types, not one.
fibs n
| n <= 1 = n
| otherwise = fibs n + fibs (n - 1)
Whoops, that's an error because you had three Ints you needed to keep track of and you chose the wrong two to go into the recursive call. Are you really claiming that types make this sort of semantic error better?You get similar problems if you were looking for the max of two mins of two lists of Ints and you accidentally wrote the min of the two mins, or if you have two functions
findMinBefore :: (Ord x) => Array Int x -> Int -> x
findMinAfter :: (Ord x) => Array Int x -> Int -> x
and you accidentally use the wrong one.Ultimately you're responding to a claim which says that there exist semantic errors, by saying that no, that's "a drastically limited idea" of what syntax can do, and results from people "choosing not to use the type system". That's a bit baffling to me. Could you clarify, so that I could see how I can eliminate these sorts of semantic errors entirely?
No I am not. I am responding to what you said, not what you want to invent after the fact. It is very simple, and is the difference between these two functions:
f :: Int -> Int -> Int -> Int -> Int -> Int
f :: Type1 -> Type2 -> Type3 -> Type4 -> Type5 -> Type6> you have five Ints and you use the wrong one for an index
In other words:
f :: Int -> Foo
doStuff :: Int -> Int -> Int -> Int -> Int -> Foo
Of course that's abstract: I meant "you" as a programmer dealing with these functions and the ints might well be a low index, a high index, and the neighborhood of a pivot index, so it's called as: doStuff lo hi (p - 1) p (p + 1)
and of course you probably wouldn't pass all three p's in -- but those are definitely three different Ints which you may have to keep track of.It sounds like your panacea here is to instead have the programmer write:
doStuff' :: Lo -> Hi -> Pminus -> Pivot -> Pplus -> Foo
The problem is, that `f` still has type `Int -> Foo` and there is still this huge semantic error of providing the wrong argument to f. So no, if you actually explicate what I said you indeed find problems much like what I "invent after the fact".Are you saying that `f` should not have input type `Int`? That input type is isomorphically non-negotiable: you're either going to write five `f` functions or you're going to have type coercions, and both ways have the problem. I really don't see anything you've said which alleviates it.
If none of what I was saying was what you thought I was saying, that's OK, mistakes happen all the time. Then, I'd just ask: in your own words, what did you think I was saying when I said, "you have five Ints and you use the wrong one for an index"?
I don't have any desire to post FUD about Haskell. I like Haskell and it's probably my favorite language at the moment. What I posted was not FUD and these replies are not "salvaging" FUD.
So, again: in your own words, what did you think I was saying?
You could use newtype.
The type system, for example, does not help you when you have five Ints and you use the wrong one for an index and the output of the procedure is thereby completely messed up at runtime. It helps to report a lot of other syntactic errors, and can be thought of as automatically providing the first half of a good test suite.
To me the real win of the type system is how it gets you breaking down real-world problems into actual code.
Programming has inertia. You can choose to either start writing garbage code until something smells right and then build organically around that smell. Totally valid. Or, you can sit and philosophize for a while about what approach you're going to take, build up some lower-level primitives that you're pretty sure you want, write some high-level overview with stub functions of what the algorithm does, connect the low-level with the high-level, and then grow organically around that. Also totally valid. For the second one, it's really nice to have type signatures. For the first, they get in the way.
Both approaches for me involve about the same amount of "wasted" time -- this is what I mean by the problem's "inertia". With the first approach, I do throw away dead code at a prodigious rate; and I often find out that I've reimplemented some popular library function which does it faster and better. With the second approach, I find that I either have to waste time redrawing my diagrams in Visio to show to a boss (so that they don't think I'm goofing off just 'cause I'm not typing). But I do like the tradeoff of repetitive-strain-injury for lots of drawings.
I think most of the mystique of Haskell comes from hackers well-versed in the first kind running into the type system as a mental roadblock which had to be overcome, forcing them to learn to plan a bit more, "here is where I/O will happen, here are the state variables I need to thread through this walk of the graph", etc. You can get that anywhere.
I really like the syntax for Haskell function-calls, `a f (g 3 + 4)` rather than `a(f)(g(3) + 4)`. I just want to figure out a way to do tensor indices alongside it, so that I could write tutorials in mathematical physics with the same syntax -- something a bit like the Structure and Interpretation of Classical Mechanics did in Lisp.