As anyone who has used C will recall, a char is just a small integer. And just the same in Haskell, a char is exactly one character. Once you understand that, this confusion makes about as much sense as expecting an integer to be "empty".
I suspect this kind of question would be better asked on the Haskell IRC channel or similar rather than trawling stack overflow for insights. If someone has the relevant missing insight they can quickly point it out and save a lot of confusion.
it does make sense. 1/0 = undefined aka null. The thing with haskell is that the concept of null is typed as part of a sum type meaning it will be handled with no runtime errors.
in Python and Haskell. In Haskell, the first one is a list of Char (which happens to be exactly the same thing as a String) the second one is a single Char, and the third one doesn't exist because you can't have an empty Char like you can an empty String, because while a String is a list and has a length, which can be zero, a Char is a character, not a list, and simply can't be "empty" in this way. In Python, all these things are strings, and single and double quotes are just alternative syntax for strings.
In C you also have a char type and you also have single-quoted char literals, and the third line is a compile-time error in C too for exactly the same reason, because a char literal represents a char, not a list of anything, and so it can't be empty in the way that a string can be empty.
From the post:
> Python doesn't distinguish between Char and String types with single and double quotes, so empty char is empty string is an empty list.
This is basically right, but the subtle misunderstanding here is that there is no such thing an empty char or indeed a char of any kind in Python, the closest you have is chr() and ord() to get integers out of strings. Indexing a string just gives you another string of length one, there's no char type in Python. If you wanted to implement cons, car, and cdr in Python such that (cons (car "abc") (cdr "abc")) = "abc" you wouldn't be able to do it in the natural way, because the type that (car "abc") needs to have doesn't exist in the language. Strings in Python are almost a list type but the elements of that list aren't representable.
So, coming from Python, the misunderstanding about why there's no "base case" for char as there is for string is understandable, but it doesn't really have much to do with Haskell or with any kind of runtime error handling.
I already 100% understand what you're saying. No need to clarify. You're misunderstanding me.
>Once you understand that, this confusion makes about as much sense as expecting an integer to be "empty".
My comment was in reference to the above. An empty number does make sense because of the of 1/0. There is nothing wrong in including a null in a set if there are operations that are illegal. Such operations can't return something so you can use a null to represent the absence of something. This is entirely different from an empty container type.
>So, coming from Python, the misunderstanding about why there's no "base case" for char as there is for string is understandable
The author is looking for a null value not an empty container type or "base case". I quote: "Haskell has no null definition of type Char,"
Basically he's looking for the equivalent of "None" in haskell. He has slight confusion in thinking that an empty container type or empty string is equivalent to a "None."
Because he literally said he's looking for a null he is indeed talking about all things associated with null.
The closest thing to null in Haskell is the maybe monad which is like null but without a runtime exception.
His confusion arises because he feels that if in haskell you can do this:
I'm pointing out the different semantics of single-quoted literals as the source of the confusion, with "empty char" being directly mentioned in the post as something that exists in Python, which, as of course you know, it doesn't.
If the confusion was about how to add a nothing value to a type, why did it arise specifically in regards to Char, and not, say, Integer? The question "why are the char types different between Haskell and Python in this way" is best answered by pointing out that Python doesn't have a char type at all, and all of these things are strings.
Of course, you're entirely correct that you can use a sum type to handle nulls.
>If the confusion was about how to add a nothing value to a type, why did it arise specifically in regards to Char, and not, say, Integer?
I illustrated earlier because of the similarity between char and str, he believed that because of recursive functions on str has base case [], he believed that char needed one too.
> If you wanted to implement cons, car, and cdr in Python such that (cons (car "abc") (cdr "abc")) = "abc" you wouldn't be able to do it in the natural way
Sure you can!
>>> car = lambda x: x[0]
>>> cdr = lambda x: x[1:]
>>> cons = lambda x, y: x + y
>>> cons (car("abc"), cdr("abc"))
'abc'
Yeah, I don't know why Prelude.head doesn't return a Maybe. Anyway, the point stands.
• In Java forgetting to check for null will crash your program.
• In C, forgetting to check for NULL will lead to undefined behavior.
• In Haskell, you either have to (a) check for Nothing, or (b) explicitly say "crash the program if this is Nothing" by using a function like fromJust or head, which internally does (a). This is always an improvement over C, and often an improvement over Java.
Side note: I like Rust's convention of consistently naming these might-crash-your-program methods "unwrap" and "expect".
I get the choice. It's unintuitive for basic types to be wrapped in a maybe mondad. People expect addition, subtraction and division to return numbers. To have division be the only operation to return an optional is a bit off.
I get the choice of why it wasn't done with haskell even though I disagree with it.
I'm saying that it makes sense to use nulls because 1/0 is an undefined operation. Therefore to represent the output of 1/0 with a null makes sense. So the existence of nulls makes sense. That is not haskell code I'm typing up there. "1/0 = undefined" is not code.
If you read my reply you will see that my statement isn't referring to an exception caused by 1/0. It's actually referring to a null exception which is completely different.
I am explicitly saying that the "null" in haskell is part of a sum type (the maybe monad) and in that case the "null" or nothing will be handled with no run time errors. You cannot have a null exception in haskell.
Never did I say Haskell has no runtime errors, and 1/0 is not an exception caused by a null. Please analyze and reread my statement.
Well, Haskell calls the empty list the "null" list (see List.null), so I could say that List.head crashes when it encounters a null. :P
Anyway, the real lesson is that even if your language has sane defaults that force you to check that your list isn't empty, or that your pointers aren't null, a bad library function like List.head can hide that check away from you and crash anyway, bringing you back to square one in terms of the type system preventing unexpected crashes.
I suspect this kind of question would be better asked on the Haskell IRC channel or similar rather than trawling stack overflow for insights. If someone has the relevant missing insight they can quickly point it out and save a lot of confusion.