4 ms·
The author is very confused. "Declarative" and "imperative" are just syntactic styles. Haskell supports both For example, the following Haskell expressions are
by jmillikin 16y ago
The author is very confused.
"Declarative" and "imperative" are just syntactic styles. Haskell supports both For example, the following Haskell expressions are equivalent:
dec :: [Integer]
dec = map (* 2) [1..10]
imp :: [Integer]
imp = do
x <- [1..10]
return (x * 2)
Due to their origins, stateful languages are traditionally imperative, and functional languages are traditionally declarative. But please don't confuse the two sets of terms.
Stateful
|
|
|
|
Imperative | Declarative
-----------------+------------------
|
|
|
|
|
Functional
- icandoitbetter 16y agoCan you explain the imperative code? I understand that it has to do with lists being monads and all, but I don't get why (return ([1..10]*2)) :: [Integer] doesn't work. What's the magic behind x <- [1..10] ?
- tkahn6 16y agoThat `do` expressions is equivalent to [1..10] >>= (\x -> return (x * 2)) and the definition of (>>=) for a List monad is instance Monad [] where return a = [a] xs >>= f = concat (map f xs) `xs` becomes bound to [1..10] `f` becomes bound to (\x -> return (x * 2)) we we map `f` over each element in the list and get mini-lists. `x` gets bound to each element in the list, x is multiplied by 2, and then returned into a list (1 becomes [2], 2 becomes [4], and so on). So we get: concat [[2],[4],[6]..[20]] And then we concatenate the mini-lists together to get. [2,4..20] As an aside, this is also equivalent [1..10] >>= return . (* 2)
- icandoitbetter 16y agoThanks!
- Dove 16y agoThanks for that. I did know about the do syntax in Haskell, but I didn't think it really made the language usefully imperative. Sure, it's okay if you're trying to kick off two or three unrelated calculations, maybe if you're after side effects. But I didn't find it much to fall back on when trying to do something complicated and having a hard time thinking about how to break down the problem without for loops and case statements and value accumulators. Maybe it's more robust than I know, but it seems like such a small piece of such a big language. Calling Haskell imperative on account of that seems like calling perl OO because you can kinda sorta do basic OO stuff most of the time. I am also having trouble understanding the claim that the ideas are orthogonal. I can see plainly enough that they aren't literally the same thing: an imperative language breaks a problem down into simpler steps, while a declarative one breaks a problem down into simpler definitions. And a stateful language accumulates progress in changing values, while a functional language does so by resolving expressions. So far so good, but I can't really decouple the concepts. How would you break a problem down by time, but track results through logical resolution? Isn't the point of a step or instruction to leave something about the state of the program changed--I mean, isn't it inherently stateful? It seems to me the advantage of imperative programming is that the steps are logically decoupled, just as the advantage of declarative programming is that the pieces are temporally decoupled. So how in the world would you make a declarative program accumulate progress via state?
- jmillikin 16y ago> But I didn't find it much to fall back on when trying to > do something complicated and having a hard time thinking > about how to break down the problem without for loops > and case statements and value accumulators. When I'm porting some stateful code to Haskell, I usually start by transcribing it as closely as possible. That means using for-loops, using stateful accumulators, and usually putting the whole thing in an IO. Once you've got a bit component compiled and working, you can start factoring out chunks into smaller, pure functions. It's the same as working out a big tangle in some string: keep working and the mess will just sort of evaporate. Of course, the difficulty here varies wildly depending on how good the original code is. Most stateful code is pretty ugly (lots of mutation, lots of tangled side-effects), but a few developers are competent enough to write good code in any language. > Maybe it's more robust than I know, but it seems like > such a small piece of such a big language. Calling > Haskell imperative on account of that seems like > calling perl OO because you can kinda sorta do basic > OO stuff most of the time. I think you're looking at the word "imperative", and assuming a lot of properties that simply aren't included. A language is not imperative or declarative; a language can support writing in imperative or declarative style, and some languages support certain styles better than others, but it's not like one is much better than the other. > And a stateful language accumulates progress in > changing values, while a functional language does so > by resolving expressions. Every program progreses by changing values. The difference is scope; a stateful language progresses by applying a sequence of mutations to a single state. Every procedure is a sequence of mutations to that state. Haskell programmers (somewhat snarkily) call that state the World. In functional programs, state is still accumulated, but in fragments. Each function has access only to what state it needs, and its contribution to the program's progress is restricted to its returned value. Only IO values have access to the World. That last sentence means that Haskell is also a stateful language. It is, effectively, a superset of C. > So far so good, but I can't really decouple the > concepts. How would you break a problem down by time, > but track results through logical resolution? Isn't the > point of a step or instruction to leave something about > the state of the program changed--I mean, isn't it > inherently stateful? The point of imperative programming isn't necessarily state, but dependency. Step 10 depends on the results of step 9, which depends on the results of step 8, and so on. It might be that no step actually requires access to the whole state -- only one little corner of it. In well-designed programs written in stateful language, a great deal of effort is spent on how to separate state from dependency. In Haskell, the compiler handles it. > So how in the world would you make a declarative > program accumulate progress via state? With parameters and the call tree, primarily.