Why is Haskell fully declarative?
Asked Answered
A

6

9

I'm not very good in understanding the difference between the imperative and declarative programming paradigms. I read about Haskell being a declarative language. To an extend I would says yes but there is a something that bothers me in respect to the definition of imperative.

When I have a datastruct and use Haskell's functions to transform that I actually just told WHAT to transform. So I give the datastruct as argument to a function and am happy with the result.

But what if there is no function that actually satisfies my needs?

I would start writing an own function which expects the datastruct as an argument. After that I would start writing how the datastruct should be processed. Since I only can call native Haskell functions I'm still with the declarative paradigm right? But what when I start using an "if statement". Wouldn't that end the declarative nature since I'm about to tell the program HOW to do stuff from that point?

Authority answered 19/10, 2016 at 11:20 Comment(3)
For what it's worth, I've always found the "imperative"/"declarative" distinction a bit artificial, as well. There are other descriptors that I've found much more objective: Haskell is pure, lazy, and strongly statically typed, and each one of those is an important pillar in my opinion.Saharanpur
After I understood the thread titled term I think I'll lean back and keep thinking the same...but first I need clearance! :PAuthority
Here is an article I wrote that might give you a better sense of what it means for code to be declarative. The TL;DR is that declarative code does not describe steps in a process, it makes invariants, guarantees, or declaration of truth. medium.com/@danielt1263/…Decidua
V
10

Perhaps this is a matter of perspective. The way I see it, there is nothing imperative about defining things in terms of other things because we can always replace something with its definition (as long as the definition is pure). That is, if we have f x = x + 1, then any place we see f z we can replace with z + 1. So pure functions shouldn't really be considered instructions; they should be considered definitions.

A lot of Haskell code is considered declarative for this reason. We simply define things as (pure) functions of other things.

It is possible to write imperative-style code in Haskell as well. Sometimes we really do want to say something like "do A, then do B, then do C". This adds a new dimension to the simple world of function application: we need a notion of 'happens before'. Haskell has embraced the Monad concept to describe computations that have an order of evaluation. This turns out to be very handy because it can encapsulate effects such as changing state.

Vent answered 19/10, 2016 at 11:51 Comment(3)
So a monad is a haskell language feature that actually ends the declarative way to the imperative?Authority
@Authority monad is a mathematical concept that can describe sequential processes. In Haskell, it's just a type class that happens to have some language support in the form of syntactic sugar (do notation).Vent
@Authority While "ends" is too strong a word -- after all Monad is just another type class, as user2297560 reminds us -- we might say that monads can be used to express imperativeness in a declarative way. The imperativeness, though, is arguably more in our heads than in the actual code, as chepner's answer emphasises.Lupitalupo
V
9

There is no if statement in Haskell, only an if expression if a then b else c, which is really equivalent to ternary expressions like a ? b : c in C-like languages or b if a else c in Python. You cannot leave out the else, and it can be used anywhere an arbitrary expression can be used. It is further constrained that a must have type Boolean, and b and c must have the same type. It is syntactic sugar for

case a of
  True -> b
  False -> c

Don't get too hung up on the label "declarative"; it's just a style of programming that the language supports. Consider, for example, a typical declarative definition of the factorial function:

fact 0 = 1
fact n = n * fact (n - 1)

This is also just syntactic sugar for something you would see as more imperative:

fact n = case n of 
          0 -> 1
          otherwise -> n * fact (n - 1)
Verst answered 19/10, 2016 at 11:31 Comment(3)
so you could say that its just like another function that returns either "this" or "that". Can you maybe add an example how it would look if it would leave the declarative paradigm? I'm ok with pseudo code here. Would be great to see what Haskell should fictionally allow if this example should go imperative.Authority
@Authority Yes, if totally could have been a function with 3 parameters, it wouldn't make a difference.Hypethral
@Verst is this last example with the matching pattern really imperative? since it's an expression :|Authority
N
7

Frankly, the term "declarative programming" is more of a marketing term than anything else. The informal definition that it means "specifying what to do, not how to do it" is vague and open to interpretation and definitely far from a black-and-white boundary. In practice, it seems to be applied to anything that broadly falls into the categories of functional programming, logic programming or the use of Domain-Specific Languages (DSLs).

Consequently (and I realise this probably doesn't qualify as an answer to your question, but still :)), I recommend you do not waste your time wondering whether something is still declarative or not. The terms imperative vs. functional vs. logic programming are already a bit more meaningful, so perhaps it's more useful to reflect on those.

Nicolella answered 19/10, 2016 at 13:38 Comment(2)
yea I found myself digging to deep and I think I won't be fully satisfiedAuthority
perhaps the only thing closest to “declarative” are DSLs, which simply hide the imperative/functional/logic based implementation.Tipi
T
3

Declarative languages are constructed from expressions whereas imperative languages are constructed from statements.

The usual explanation is what to do versus how to do it. You've already found the confusion in this. If you take it this way, declarative is using definitions (by name) and imperative is writing definitions. What is a declarative language then? One which only names definitions? If so then the only Haskell program you could write is precisely main!

There is a declarative way and an imperative way to have branching, and it follows directly from the definition. A declarative branch is an expression and an imperative branch is a statement. Haskell has case … of … (an expression) and C has if (…) {…} else {…} (a statement).

What is the difference between expressions and statements? Expressions have a value whereas statements have effects. What is the difference between values and effects?

For expressions, there is a function μ which maps any expression e to its value μ(e). This is also called the semantic, or meaning, and is ideally a well-defined mathematical object. This way of defining values is called denotational semantics. There are other methods.

For statements, there is a state P immediately before a statement S and a state Q immediately after. The effect of S is the delta from P to Q. This way of defining effects is called Hoare logic. There are other methods.

Tusche answered 19/10, 2016 at 13:17 Comment(3)
so when using statements whichs core semantic is the effect of a preState to a postState I'm moving in a imperative situation? Whilst using expressions is the declarative way since I'm able to actually declare the result by myself without the need to call the function (fun x = x + 1 would be the same as using 1 as the resource and just declaring it as 2 since this would be the same expression result as when using the pure function mentioned before)Authority
It is declarative if it is an expression. 1 + 1, fun 1, and 2 are all expressions for the integer 2. As others point out, there are various uses of "declarative" and "imperative"; my objective is to offer a use which has precise meaning. There are other qualities expressions may have. If an expression E is composed of sub-expression M, and if any expression N which denotes the same value as M may be substituted for M without changing the meaning of E, then N is referentially transparent in E. In other words, it matters what you say rather than how you say it.Tusche
I wish down-voting required the person to leave a comment.Tusche
V
0

You can't use an "if statement" in Haskell, because there is none. You can use an "if-expression"

if c then a else b

but this is just syntactic sugar for something like

let f True a b = a; f False a b = b in f c a b  

which is again fuly declarative.

Vengeful answered 19/10, 2016 at 18:41 Comment(1)
and that is fully imperative: let f True a b = a; f False a b = b in f c a b you are explicitly stating how it should do something.Meleager
T
0

Haskell is not fully declarative. It is purely functional, but that doesn’t necessarily imply fully or purely declarative. Even if it is widely considered to be declarative. In a way, it is imperative, without mutations, i.e. every function declaration is still a series of imperatives of how to compute A from B — now, in the human sense of the word ‘declarative’, compute A from B is not declarative, unless you mean a declaration of imperatives. Its runtime doesn’t exhibit any behavior that adds on top of that basic declaration (of imperatives), it just makes sure side effects are pure, and makes some reorderdings to make evaluation lazy. Perhaps this laziness of evaluation makes it declarative in the world of imperative languages in the sense that the runtime figures out from the programmer’s declarations how to automagically make the code more efficient without the programmer having to specify evaluation order and eagerness. But I guess even compilers such as GCC can do this to an extent, and the JVM JIT.

However, if you look at a language such as Prolog (or Curry, which is Haskell with Prolog capabilities), when you declare how to compute A from B, you typically also automatically declare how to compute B from A, and how to generate all/some pairs of A and B, and how to verify that a given (A,B) belongs to the set/relation defined by the original declaration.

Now, if you look at it from a human perspective, that is far closer to being declarative in the truer sense of the word. In human reality, all instructions to perform something, are interpreted by humans more or less like Prolog does. In addition, sequences of imperatives are even re-interpreted as declarations, and declaratives are automatically converted into executable steps.

Curry, which is something like Haskell++, can perform in both the pure FP as well as declarative Prolog worlds. (shameless plug)

Tipi answered 24/1 at 17:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.