Live data from Hacker News

The Day Python Embarassed Imperative Programming

the-27th-comrade.appspot.com

51–60 of 80 posts

Re: The Day Python Embarassed Imperative Programming

#51
post #44

Earlier quoted context omitted.

Poorly worded, but the point is that every reference in Python, like in Java, ALGOL 60 and countless other languages, may be of a certain type, or point to None. In Haskell, save for a caveat[1], this doesn't happen, and you represent nullability (failure, usually) with types like Maybe or Either, when you want to . Those happen to be monads, too, but you can use them without the monadic operators. [1] The caveat is…

Null is an interesting exception in languages with static typing such as Java. But there is no static typing in Python. Literally any variable can hold any value of any type. None is not nearly so special there, since you can also assign 3 to any variable, or the identity function, or a string containing the answer to the question of life, the universe, and everything. In languages like Java, null has special semanti…

Yes, actually, you are right. It's all the same in Python because the references can always point to any value, and None is just a value of the NoneType.

And due to Python's runtime types, it wouldn't matter either way, because even if None only existed within the context of a Maybe type, you could still just apply any operation on it and have crash at the first method call on it.

Re: The Day Python Embarassed Imperative Programming

#52

Earlier quoted context omitted.

wouldn't it be better to a) code f defensively in the first place, and b) not call f with invalid parameters?

> wouldn't it be better to a) code f defensively in the first place, In Haskell, you don't have to. If your function takes a String as an argument, for instance, the compiler will ensure that it never receives a null instead. It will always receive an actual String, because normal types are non-nullable in Haskell. You have to explicitly wrap a type in a Maybe if you want to add nullability, and `Maybe String` is a c…

I agree, but that particular issue can be fixed with a type system tweak instead, to treat nullability as a type modifier, vaguely like constness, which can then be statically enforced. Cyclone adds nullability annotations to C, for example, and Ada has a "null exclusion" type modifier.

Re: The Day Python Embarassed Imperative Programming

#53

Earlier quoted context omitted.

wouldn't it be better to a) code f defensively in the first place, and b) not call f with invalid parameters?

> wouldn't it be better to a) code f defensively in the first place, In Haskell, you don't have to. If your function takes a String as an argument, for instance, the compiler will ensure that it never receives a null instead. It will always receive an actual String, because normal types are non-nullable in Haskell. You have to explicitly wrap a type in a Maybe if you want to add nullability, and `Maybe String` is a c…

Python doesn't have nullability, you must always pass some object; None is just an object like any other /pedant.

Re: The Day Python Embarassed Imperative Programming

#55
post #15

Earlier quoted context omitted.

It does come with an overhead for a beginner, to be sure. But because it is a consistent abstraction we can build idioms on top of the concept of a monad, and in doing so it actually becomes easier to reason about. The best things in life have a learning curve. Edit: Wow, I was downvoted for this?

(not downvoter) I come to completely the opposite conclusion: http://williamedwardscoder.tumblr.com/post/18319031919/progr... There's nothing stopping someone writing a haskell-alike with readable syntax as long as they stay away from trying to create terms like monads to explain things that don't need explaining ;)

Monads only need a lengthy explanation if you don't understand that they are a typeclass in Haskell. The monad laws you can take to be principles on which to correctly implement them, but they aren't necessary for their use.

Besides, that whole post just gave me the impression that you haven't done the minimum necessary to understand Haskell programs. You claim that there is no immediate visual grouping of the expressions, yet you seem to gloss over all the pattern-based definitions of functions.

Now, if you find using such lengthy sequences of patterns to define your functions unsavory, you can use case expressions, which... require indentation for their cases.

On most respects, it just comes down to the fact that Haskell is different, and it takes a bit of reading to accustom oneself to it.

edit: It was a tad too defensive before. Sorry 'bout that.

Re: The Day Python Embarassed Imperative Programming

#56

Earlier quoted context omitted.

It is not only cleaner, it is also safer. In Python you have to add checks explicitly, or your program may try to execute a method on None . When using the Maybe or Either monad in Haskell, failure is always handled. Say that you have a sequence of three functions that return a Maybe value: do b Now, suppose that in a particular case f a returns Nothing , then the whole do-expression will evaluate to Nothing and g No…

One could say the problem is using None for indicating errors. Python does have exceptions, which also prevent further statements from being executed. try: b = f(a) c = g(b) return h(c) If f(a) raises an exception, g and h don't get executed. None should be returned when it's a valid value (say, in search() if it doesn't find anything), and in those cases it makes sense to have explicit handling.

That's a fair point. On some level a try block resembles a monad that encapsulates success/failure. However, it is not general, e.g. it does not provide a solution if you want to chain computations where returning None/Nothing is valid (e.g. a Map lookup in Haskell).

The nice thing about monads is that it provides an abstraction on sequences of computations, involving failure, error, state, effects, etc. Though, it can get ugly at times when you want to use multiple monads simultaneously (via monad transformers).

Re: The Day Python Embarassed Imperative Programming

#57

Earlier quoted context omitted.

> wouldn't it be better to a) code f defensively in the first place, In Haskell, you don't have to. If your function takes a String as an argument, for instance, the compiler will ensure that it never receives a null instead. It will always receive an actual String, because normal types are non-nullable in Haskell. You have to explicitly wrap a type in a Maybe if you want to add nullability, and `Maybe String` is a c…

I agree, but that particular issue can be fixed with a type system tweak instead, to treat nullability as a type modifier, vaguely like constness, which can then be statically enforced. Cyclone adds nullability annotations to C, for example, and Ada has a "null exclusion" type modifier.

The advantage to Haskell's type constructor approach, though, is extensibility. Making nullability a language keyword like `const` requires a change to the fundamental grammar of the language. In Haskell, `Maybe a` is just another data type, defined entirely in Haskell itself. This opens the door to allowing users of the language to create arbitrary type system constraints without having to modify the compiler to support them.

Re: The Day Python Embarassed Imperative Programming

#58

Perhaps the author is just glossing over the bigger picture for the sake of explanation, but it's a bit of a narrow view of monads to say that they are just "conditional function calls". That's true if the monad in question is Maybe, Either e, or (if you're squinting at it just right) []. But >>= in the State s and IO monads, for instance, has little to do with conditionally calling functions; there, it's more about…

m a -> (a -> m b) -> m b Okay, so what does this mean? I thought it was `f x -> x * x` is a function definition, right? Or am I completely mistaken here? Because in the above code, what is the function name, the parameter and the return value? I know "everything is a function" in Haskell but I really can't see through the multiple arrows here. Any help?

This is one of those things that functional-programming people seem to "get" without ever making the explanation very clear.

First of all, this is a function declaration (ie. prototype), not a definition. So this is describing a function type, not a function implementation. But that doesn't help very much because it's still not very obvious what the function type means.

The shortcut way to understanding Haskell function declarations is this; if you see:

  a -> b -> c -> d
in your head, think of it as:

  f(a, b, c) -> d
In other words, it is a function that takes three parameters of types a, b, and c and returns type d. Everything before the final -> is a parameter and the final type is a return type.

My "shortcut" isn't literally true, obviously. Here is the gory detail.

In Haskell, every function takes at most one parameter. Functions of multiple parameters do not exist; they are simulated through a technique called "currying." When you think you're calling a function of more than one parameter, you're actually calling a series of functions, each of which takes exactly one parameter. So in Haskell, if you call:

  f a b c
This is actually parsed as

  ((f a) b) c
Or in more C-like notation:

  f(a)(b)(c)
In other words, you call a function with a single parameter "a", which returns a function that you call with a single parameter "b", which returns a function that you call with a single parameter "c."

Likewise, the Haskell type declaration:

  a -> b -> c -> d
Is actually right-associative, so it's parsed as:

  a -> (b -> (c -> d)))
Which is why the whole thing works.

So to parse:

  m a -> (a -> m b) -> m b
Think of it as a function that would be called like so:

  f(m a, g) -> m b
Where g is a function that would be called like so:

  g(a) -> m b
The "m a" and "m b" business you can think of as being a lot like M and M in C++.

Re: The Day Python Embarassed Imperative Programming

#59
post #45

Earlier quoted context omitted.

wouldn't it be better to a) code f defensively in the first place, and b) not call f with invalid parameters?

No? The point is to factor out the repeated check-for-None code into one place to reduce redundancy and unclutter the algorithmic code in f. Separation of Concerns.

Writing wrapper functions that just calls a function provided as an argument seems insane to me.

If the code really cares what it's getting, it should not only be checking for None, but also that the arguments it is called with are valid.

I still fail to see why you would write a function like this at all.

Re: The Day Python Embarassed Imperative Programming

#60
post #15

Earlier quoted context omitted.

It does come with an overhead for a beginner, to be sure. But because it is a consistent abstraction we can build idioms on top of the concept of a monad, and in doing so it actually becomes easier to reason about. The best things in life have a learning curve. Edit: Wow, I was downvoted for this?

(not downvoter) I come to completely the opposite conclusion: http://williamedwardscoder.tumblr.com/post/18319031919/progr... There's nothing stopping someone writing a haskell-alike with readable syntax as long as they stay away from trying to create terms like monads to explain things that don't need explaining ;)

I don't think that's a fair comparison. Here's a toy trie implementation I've just thrown together in Haskell. It may not be perfect, but I think it's more comparable to your Python.

http://lubutu.com/media/temp/trie.hs

Post reply on HN