[Haskell-cafe] Bool is not...safe?!

Joachim Durchholz jo at durchholz.org
Sun Jul 8 08:28:04 UTC 2018

Am 08.07.2018 um 09:43 schrieb Paul:
> @Joachim.
> Hello again. Let’s talk about Haskell and not persons. I suppose that my 
> not good English may lead to misunderstanding. Excuse me, in this case. 

Nah, you are mixing up terminology that is easily looked up.

> If you allow me, I would like to show reasons why I said “imperative” 
> and not declarative.
> In Haskell I can write:
> factorial 0 = 1
> factorial n = n * factorial (n - 1)
> I can call it: factorial 5 => 120.
> And often I meet in Web similar examples with note: “You see – Haskell 
> is declarative language, it really looks declaratively”.

"It's declarative because it looks declarative" is a circular argument, 
and misses whatever definition of "declarative" was actually used.

BTW you don't define it either. Arguing around an undefined term is 

> We see principal difference:
>  1. In Haskell we map inputs (arguments) to result. In Prolog we define
>     not mapping but *relation*, which is *bi-directional* while Haskell
>     is *one-directional*, like C, Java, etc. We can find also arguments
>     from result in Prolog.

Yeah, that's the defining feature of Prolog-style languages.
And where the pure subset of Prolog is conceptually different from the 
pure subset of Haskell.

>  2. In Haskell like in any imperative language we describe exact
>     algorithm/solution. We define *HOW*. In declarative language we
>     define *WHAT*: we *restrict result* and don’t know actually how it
>     will be evaluated.
>  3. In Haskell all is evaluated as you wrote code. Exactly. No magic.

Just as much or little magic as in Prolog.
Hey, FORTRAN's expression sublanguage was considered magic at the time 
FORTRAN was written in all upper-case letters: You just write down the 
expression, and the compiler magically determines what data to move 
where to make it all happen.

So... "no magic" is not suitable as a criterion, because what's magic 
and what's not is in the eye of the beholder.
Having written a Prolog interpreter, Prolog is as non-magical as C or 
C++ to me; in fact I find Haskell's implementation slightly "more magic" 
simply because I have not yet written a run-time for a lazy language, 
but not *much* "more magic" because I happen to know the essential 
algorithms. Still, Haskell's type system and the possibilities it offers 
are pretty baffling.

>     But in Prolog we restrict some *solver* to find answer (or answers).

Except in cases where the solver is too slow or goes into an endless 
loop. At which point we start to mentally trace the solver's mechanisms 
so whe know where to place the cut, and suddenly that magic thing turns 
into a complex-but-mundane machinery.

>     In the example this solver is called CLP(FD). Sure, there are other
>     solvers. Modern Prolog systems contain a lot of solvers, expert
>     system engines, etc, etc. So, Haskell has not solvers/engines.
>     Prolog has. Prolog is DSL for solvers. Interesting analogue is SQL
>     as DSL for RDBMS😊


> If we want to achieve the same magic in Haskell, we must write such 
> solver explicitly (ie. “how”).

I got pretty disillusioned about Prolog when I tried to use it for 
real-world problems. So I don't consider it much of a loss if you have 
to code a solver if you want a solver.

> Another interesting speculation about real nature of Haskell is List 
> monad. We often see “Haskell is declarative because it has backtracking”

Where did you see that claim?
Because at face value, this claim is hogwash. Haskell's semantics does 
not have backtracking at all, and I doubt you'll find any runtime that 
uses backtracking even as a mere implementation strategy.

> with attached some example of List monad/do/guard.

Which is unrelated to backtracking.

 > But we can say that
> Python is declarative because it has permutations in its itertools 
> module which allows to solve similar tasks.

Python is a language where even class and function "declarations" are 
executable statements (making it really hard to work with 
mutually-referencing declarations so this isn't a mere theoretical 
quibble but a hard, real-life problem), and that's as non-declarative as 
you can get without becoming totally useless.

I'm awfully sorry, but this is the most ridiculous claim I heard in a 
long time.
I am even more sorry but I do have to talk about humans: Please get your 
definitions right. It's easy, even if English isn't your native language 
(it isn't mine either).

  We understand that List
> monad is not backtracking, and “guard” is similar to Smalltalk “ifTrue” 
> – no magic, no real backtracking.

Well if that example was hogwash, why did you bring it up?

  But like Python itertools can be used
> to solve some logic tasks in bruteforce/permutations style (as many 
> other modern languages with sequences, F#, for example).

Sure. You can to functional, pure, declarative, context-free etc. stuff 
in imperative languages no problem. You can even do that in assembler - 
large systems have been built using such approaches.

That doesn't make the languages themselves functional/pure/etc.; the 
definition for that is that the language does not allow doing anything 
that is not functional/pure/whatever.
Very few languages are really one of these properties, it's almost 
always just a subset of a language; still we say that Haskell "is pure" 
because the pure subset is very useful and in fact most programmers 
avoid going outside that subset. (People rarely use UnsafeIO. Whether 
_|_, or equality under lazy evaluation, are compatible with purity 
depends on details of your definition of pure, some people would say 
yes, some would say no.)

> You said that “imperative” term is based on term of side-effects. May be 
> I’m seriously wrong, but please, correct me in this case. IMHO 
> side-effects are totally unrelated to imperative/declarative 
> “dichotomy”.

That depends on what you consider declarative.
I am not aware of any widely-agreed-upon definition, so you have to 
provide one before we can talk.

> also I see
> main :: IO ()
> in Haskell.

As far as I know, the IO monad does not execute any IO. It merely 
constructs descriptions of what effects to invoke given what descriptions.
The actual execution happens outside the program, in the runtime.

That's why UnsafeIO is unsafe: It triggers IO execution inside the pure 
Haskell world, possibly creating impurities where the language semantics 
assumes purity (IOW you may find that compiler optimizations may change 
the behaviour of the program).

> When I was student, criteria 
> of declarative/imperative was: functional, procedural, OOP languages are 
> imperative, due to one-directional evaluation/execution and you code HOW 
> to be evaluated, but declarative is bi-directional, you code relations 
> (WHAT), between predicates and apply some restrictions.

That's Prolog's idea of "declarative".
HTML, CSS, and most Turing-incomplete languages are considered 
declarative, too.
Some people define "declarative" to be exactly the opposite of "imperative".

It's really a matter of definition.

More information about the Haskell-Cafe mailing list