> To get some order in in the different types of declarative languages,
> my question is, if the following diagram is correct and complete.
>
>
> --- predicative languages
> |
> |
> declarative -|
> languages | --- single asignment languages
> | |
> --- functional languages -|
> |
> --- applicative languages
>
In my opinion a classification must contain at least two layers:
- a generic term for "non-imperative languages" (this is the common criterion),
- terms for the different types of non-imperative languages.
I found a lot of inconsistent classifications, in which the same terms are
often used in contradictory ways:
----+------------+------------------+-----------------------+-----------------
GENERIC TERM term for term for term for
FOR "NON- language of type: language of type: language of type:
IMPERATIVE
LANGUAGE": f (g, h (i, j)) .-. .-. .-. "find x in order
|A|--->|B|-->| | .-. to make true:
`-' | `-' |C|-->|D| 4 = 1 + x"
`------->| | `-' e.g. written as:
(no.) `-' "add (4, 1, x)"
----+------------+------------------+-----------------------+-----------------
(1) DECLARATIVE functional dataflow logic
(2) - functional, - declarative,
applicative predicative
(3) DECLARATIVE functional dataflow parallel logic
(4) FUNCTIONAL, - - -
APPLICATIVE,
DATAFLOW
(5) FUNCTIONAL IN FUNCTIONAL IN - -
WIDER SENSE, NARROWER SENSE
APPLICATIVE
I prefer no. (1). All these languages have in common, that they describe only
*data dependencies*, not the order of an execution. They all don't have
variables with changing states. Therefore they all are
*single-assignment-languages*. Multiple-assignment-languages need variables and
states, I would therefore classify them generally as *imperative* languages.
I am interested in other opinions about the issue, please post or mail them.
bye,
--
Wolfgang Melchert e-mail: m...@iitb.fhg.de
Fraunhofer-Institut fuer Informations- und phone: +49-721-6091-264
Datenverarbeitung (IITB), Fraunhoferstrasse 1 fax: +49-721-6091-413
D-7500 Karlsruhe 1, GERMANY
]----+------------+------------------+-----------------------+-----------------
](1) DECLARATIVE functional dataflow logic
...
I prefer the term "constraint language" to "logic programming
language". Formal logics include functional and imperative languages
(eg: the lambda calculus is part of the lambda logic). Prolog, the
first "logic programming language" is more properly a a _predicate
logic_ programming language. But predicate logic is not the only type
of logic. The term "constraint" emphasises that the unique feature of
the language is that it involves solving problems by writing a set of
constraints that the problem must meet.
Also, the only difference between a functional language and a dataflow
language is that the literature for a dataflow language emphasises the
flow-diagram as a way of viewing what is going on. The paradigm of
viewing a program as a flow-diagram is orthogonal to whether a
language is functional, constraint, or imperative. An imperative
language viewed as a flow diagram is a traditional flow-chart
language. A constraint language viewed as a flow-diagram produces a
language where programs are viewed as constrained circuits -- rather
like data-flow languages, but the data can flow both ways, and sort of
settles into a solution state.
I propose then, a diagram that looks like this:
functional constraint imperative
abstract FP Prolog C
diagram SISAL (no well-known ? FORTRAN ?
ones I'm aware of)
where the term "abstract" just means that the domain of the language
is some sort of non-visual abstraction. The term "diagram" doesn't
mean that the language is a "visual programming language", it just
means the the language is designed/described with the notion of the
computing domain being a diagram of some sort. In other words, a
program in a diagram language describes a diagram.
--
David Gudeman
gud...@cs.arizona.edu
noao!arizona!gudeman
In article <72...@optima.cs.arizona.edu> gud...@cs.arizona.edu (David Gudeman) writes:
>I prefer the term "constraint language" to "logic programming
>language". Formal logics include functional and imperative languages
>(eg: the lambda calculus is part of the lambda logic). Prolog, the
>first "logic programming language" is more properly a a _predicate
>logic_ programming language. But predicate logic is not the only type
>of logic. The term "constraint" emphasises that the unique feature of
>the language is that it involves solving problems by writing a set of
>constraints that the problem must meet.
To me, a declarative language is one in which
the basic paradigm consists of
1) declaration of definitions (with complex definitions constructed
via the composition of simpler definitions)
2) request to make explicit some implication of the definitions.
E.g. functional programming:
1) define some functions
2) write an expression representing the result of a functional mapping
applied to some object, so that the computer makes the result
explicit.
E.g. logic programming
1) define some relations
2) write expression (goal) representing a criteria which
for logical variable binding, so that the computer
makes explicit some of the bindings which fall
into the implied category.
I don't consider applicative languages to be _inherently_ declarative.
For instance, I don't see what is declarative about lambda calculus,
unless you can relate the syntactic idea of lambda abstraction
to the semantic notion of function abstraction (which few language
designers bother to do).
Frank Silbermann f...@cs.tulane.edu
Tulane University New Orleans, Louisiana USA
]----+------------+------------------+-----------------------+-----------------
](1) DECLARATIVE functional dataflow logic
...
I prefer the term "constraint language" to "logic programming
language". ...
"constraint language" has its own specific meaning. The terminology
may not be ideal, but "logic programming language" is the accepted
term for languages like Prolog.
I think there is another difference between (pure) functional and "dataflow"
(i.e., "definitional" languages like VAL, Id, SISAL etc.): the dataflow
languages I know of (VAL, Id, and I suppose SISAL) have an iteration
construct, akin to a loop, to control the execution, whereas in a purely
functional language you must always use recursion for this. If we view the
execution of a program as a dynamic buildup and reduction of an acyclic data
dependence graph, then the iteration construct builds the graph bottom-up
whereas the recursion builds it top-down. Cf. "data-driven" vs.
"demand-driven" execution in dataflow machines.
Bjorn Lisper
"Constraint language" has the specific meaning of a language that
solves problems using constraints, just as I said. The literature on
constraint languages says that Prolog is a constraint language, but
that there are other possible constraint languages not based on Horn
clause logic, nor even predicate logic (but they are still
declarative). Also, many people in the "logic programming language"
community have dropped the term "logic" in favor of "constraint".
Forgive me if I've misinterpreted your point, but wasn't the relation
of semantic and syntactic properties of the untyped lambda calculus
solved by Scott[1]? Lambek and Scott[2] provide a survey which includes
a categorical model of the typed lambda calculus, and Ong[3] provides a
congruence for the lazy lambda calculus.
---
David Lester, Manchester University, UK.
[1] Scott, D, "Continuous Lattices", LNM 274, 1972.
[2] Lambek, J, and Scott, PJ, "Introduction to higher order
categorical logic", 1986.
[3] Ong, CHL, "The lazy lambda calculus", PhD thesis, Imperial
College, London, 1988.
> Bjorn Lisper
I'm not sure what you mean. In Id, at least, loops are explained as syntactic
sugar for tail-recursion, so there is no difference between loops and the
corresponding recursive forms.
Nikhil
> "constraint language" has its own specific meaning. The terminology
> may not be ideal, but "logic programming language" is the accepted
> term for languages like Prolog.
Conventional logic programming languages solve constraints over the
domain of labelled trees (aka first-order terms) --- the constraint
solving procedure is called "unification" [*]. As such, logic programming
languages are a special case of constraint programming languages.
[*] In practice, most systems use unification-without-occur-check,
which amounts to constraint solving over rational terms (i.e.,
terms with "back edges").
This is probably straying from the topic of this newsgroup, so I've
redirected followups to comp.lang.prolog.
--
Saumya Debray CS Department, University of Arizona, Tucson
internet: deb...@cs.arizona.edu
uucp: uunet!arizona!debray
In article <30...@m1.cs.man.ac.uk> dle...@cs.man.ac.uk (David Lester) writes:
> Forgive me if I've misinterpreted your point,
> but wasn't the relation of semantic and syntactic properties
> of the untyped lambda calculus solved by Scott[1]?
>
> [1] Scott, D, "Continuous Lattices", LNM 274, 1972.
For functional programming,
I don't think "the" untyped lambda calculus is very relevant.
In the work I've seen, Scott dealt with a language
in which _all_ objects are functions.
This is not relevant to a language which has been
enriched with constants, lists, booleans, etc.
It is true that _some_ of the additional operations
can be simulated in lambda calculus. It has long
been part of functional programming folklore
to associate lambda expressions with TRUE, FALSE,
and IF/THEN/ELSE, and to show that beta-reduction
implements the IF/THEN/ELSE. Still, this approach
is inadequate for explaining the various "enriched" lambda calculi.
For instance, what about a lambda expression to test
whether two atoms-encoded-as-lambda-expressions are equal?
What about a lambda expression to test whether
another an expression does indeed represent a boolean value?
Such essential tests are quite difficult to implement
if one insists on mapping everything back to pure lambda calculus.
The assumption that enriched lambda calculi are really
just sugars for pure lambda calculus leads to other misunderstandings.
E.g., many functional programmers have asserted that
the leftmost rule will terminate whenever termination is possible,
because this is true in the pure lambda calculus.
It is certainly _not_ true in a system enriched
with parallel boolean connectives (e.g. an OR
which returns TRUE if either argument is TRUE,
even if the other argument diverges).
To be sure, Scott's work does generalize
to domains in which some elements are _not_ functions.
One _can_ use simple domain theory to model
various more suitable enriched lambda calculi.
The key is to:
1) specify the intended domain model;
2) demonstrate that each primitive is continuous over its domain; and
3) show that each primitive is fully implemented
(at least for all basis elements of its domain)
by its simplification axioms.
How many functional language designers bother to take
even the first step?
> Lambek and Scott[2] provide a survey which includes
> a categorical model of the typed lambda calculus,
> [2] Lambek, J, and Scott, PJ, "Introduction to
> higher order categorical logic", 1986.
Because I have not yet mastered category theory,
I have not followed what Lambek and Scott did
wrt typed lambda calculus. For those who do understand this work,
I am curious as to whether this model adequately
treats Y-combinators, which are essential to the use
of typed lamda calculus as the basis for functional programming.
> and Ong[3] provides a congruence for the lazy lambda calculus.
>
> [3] Ong, CHL, "The lazy lambda calculus", PhD thesis,
> Imperial College, London, 1988.
The word "lazy" is sometimes (inappropriately?) used
to describe normal-order evaluation.
How does the _lazy_ lambda calculus
differ from the ordinary lambda calculus,
for which normal-order reduction is assumed?
Having a term rewriting/graph rewriting culture, we make a distinction
between functional and applicative styles distinguished by the arities of
the functions used.
Miranda is an applicative-style language: all the function definitions
are really rules for a hidden binary apply function as in the lambda calculus.
All other symbols have arity zero. Given a rule
f x y = ...
it is possible to use f alone, (f a), (f a b), ...
Clean, from Nijmegen University, is a functional-style language. Functions
may have any arity: Given
a rule
F x y -> ...
terms involving F always take two arguments. (Well, in fact it is possible
to use curried forms, with an explicit AP function, but they lead to code
which will build the functional form when enough arguments are provided).
Also:
In article <1991Sep17.2...@crl.dec.com>, nik...@crl.dec.com (R.S. Nikhil) writes:
>
> > I think there is another difference between (pure) functional and "dataflow"
> > (i.e., "definitional" languages like VAL, Id, SISAL etc.): the dataflow
> > languages I know of (VAL, Id, and I suppose SISAL) have an iteration
> > construct, akin to a loop, to control the execution, whereas in a purely
> > functional language you must always use recursion for this. ...
>
> > Bjorn Lisper
>
> I'm not sure what you mean. In Id, at least, loops are explained as syntactic
> sugar for tail-recursion, so there is no difference between loops and the
> corresponding recursive forms.
>
> Nikhil
>
But does the average person think in terms of tail recursion when they
write a loop? I realise the easiest way to provide seamtics is via recursion,
but then denotational semantics can be seen as giving a functional/declarative
interpretation of imperative languages as well.
John
Indeed.
Denotational semantics was invented to give
declarative (functional) definitions
to nondeclarative languages.
Similarly,
when we view a lambda calculus as a theory in logic
(i.e. a set of axioms as to what converts to what),
we give a declarative (logical) description
of the lambda calculus' _operational_ semantics.
It's a declarative description of LC's _interpreter_,
I don't think this implies anything about
whether the lambda calculus itself is declarative.
To me,
a language is declarative if the language notations themselves
correspond fairly directly to well-understood mathematical
or logical constructs (e.g. functions, predicates, numbers, booleans, etc.)
This definition still leaves room for us to have fun
fighting over which languages are declarative,
since the phrases "fairly directly" and "well-understood"
are open to interpretation!
>I'm not sure what you mean. In Id, at least, loops are explained as syntactic
>sugar for tail-recursion, so there is no difference between loops and the
>corresponding recursive forms.
Indeed, but tail-recursive functions are a *restricted* class of recursive
functions allowing the "reverse" interpretation (bottom-up) that I
indicated.
Think of imperative flowchart programs. Nobody would think of them as "pure
functional" - yet, you can give a purely recursive formulation of each such
program.
I would put "dataflow" languages somewhere in-between imperative and
"purely" functional programs.
Bjorn Lisper
OK, we agree to differ.
|> In the work I've seen, Scott dealt with a language
|> in which _all_ objects are functions.
|> This is not relevant to a language which has been
|> enriched with constants, lists, booleans, etc.
I think that "not relevant" is, perhaps, a bit strong; I'd
prefer "not immediately relevant".
|> [Discussion of why pure LC models of atomic constants causes
|> problems deleted.]
Agreed.
|> The assumption that enriched lambda calculi are really
|> just sugars for pure lambda calculus leads to other misunderstandings.
Indeed.
|> E.g., many functional programmers have asserted that
|> the leftmost rule will terminate whenever termination is possible,
|> because this is true in the pure lambda calculus.
If functional programmers assert this "because" of results in the pure
LC, then they are wrong, aren't they? ...
|> It is certainly _not_ true in a system enriched
|> with parallel boolean connectives (e.g. an OR
|> which returns TRUE if either argument is TRUE,
|> even if the other argument diverges).
... and that was the counter-example.
However, Klop[1] might be a good place to start, in order to
find out what restrictions on the delta rules are needed to
preserve most of the results from pure LC.
|> To be sure, Scott's work does generalize
|> to domains in which some elements are _not_ functions.
|> One _can_ use simple domain theory to model
|> various more suitable enriched lambda calculi.
|> The key is to:
|> 1) specify the intended domain model;
|> 2) demonstrate that each primitive is continuous over its domain; and
|> 3) show that each primitive is fully implemented
|> (at least for all basis elements of its domain)
|> by its simplification axioms.
Exercise 9 of Chapter 13 of Stoy's book[2] gives an example of an LC
with lazy and strict function calls along with constants; and asks the
student to prove a congruence with a continuation semantics.
I set this example to undergraduates, when I was "teaching assistant"
to Joe, so it can't be that difficult.
|> How many functional language designers bother to take
|> even the first step?
I've no idea.
|> > Lambek and Scott[2] provide a survey which includes
|> > a categorical model of the typed lambda calculus,
|> > [2] Lambek, J, and Scott, PJ, "Introduction to
|> > higher order categorical logic", 1986.
|>
|> [asking about treatment of Y]
There is a finite iterator construct, which models F^n rather than
F^\infty. The extension to include Y in this model is, I think, due
to Curien[3].
|> > and Ong[3] provides a congruence for the lazy lambda calculus.
|> >
|> > [3] Ong, CHL, "The lazy lambda calculus", PhD thesis,
|> > Imperial College, London, 1988.
"lazy" is used here to talk about reduction to WHNF rather than HNF.
Yes, it includes fix.
I'm working from memory for Klop, Curien and Ong as my previous
employer repossessed my collection of papers and books.
Hope this helps,
---
David Lester, Manchester University, UK.
ps Perhaps it would help if you specified which language features you
wish to model, and what mathematical models are acceptable to you as
a semantics.
[1] J Klop, "Combinatory reduction Systems", PhD, Utrecht, 1980.
[2] JE Stoy, "Denotational Semantics", MIT Press, 1977.
[3] P-L Curien, "Combinateurs cate'goriques, algorithmes se'quentiels,
et programmation applicative", PhD, Universite' Paris VII, 1983.
> In article <1991Sep17.2...@crl.dec.com>, nik...@crl.dec.com (R.S. Nikhil) writes:
> >
> > > I think there is another difference between (pure) functional and "dataflow"
> > > (i.e., "definitional" languages like VAL, Id, SISAL etc.): the dataflow
> > > languages I know of (VAL, Id, and I suppose SISAL) have an iteration
> > > construct, akin to a loop, to control the execution, whereas in a purely
> > > functional language you must always use recursion for this. ...
> >
> > > Bjorn Lisper
> >
> > I'm not sure what you mean. In Id, at least, loops are explained as syntactic
> > sugar for tail-recursion, so there is no difference between loops and the
> > corresponding recursive forms.
> >
> > Nikhil
> >
>
> But does the average person think in terms of tail recursion when they
> write a loop? I realise the easiest way to provide seamtics is via recursion,
> but then denotational semantics can be seen as giving a functional/declarative
> interpretation of imperative languages as well.
>
> John
And, in article <1991Sep20.1...@sics.se>, bjo...@sics.se (Bj|rn Lisper) writes
> Indeed, but tail-recursive functions are a *restricted* class of recursive
> functions allowing the "reverse" interpretation (bottom-up) that I
> indicated.
>
> Think of imperative flowchart programs. Nobody would think of them as "pure
> functional" - yet, you can give a purely recursive formulation of each such
> program.
>
> Bjorn Lisper
I think perhaps Bjorn and John misunderstand the very close correspondence between loops and
tail recursion in Id. My original response to Bjorn was trying to make the technical point
that there is absolutely NO "top-down" vs. "bottom-up" difference between loops and tail
recursions in Id, in the way the computations unfold, as Bjorn suggests. There is no such
difference in the semantics, nor in the implementations (and, to get non-technical, nor in
the way programmers think about Id loops).
Your analogies with denotational semantics/recursive formulations to give ``functional''
explanations to imperative programs do not hold here. In Id, the BEGINNING programmer is
shown the correspondence between an Id loop and its tail recursive form, in his very first
lecture on loops. The correspondence is direct and obvious, we explain it in less than 5
minutes (students already know about recursion), and it occupies less than half a page of
easy reading in the Id reference manual. So, when I said syntactic sugar, I really did mean
syntactic sugar.
I don't think you can say the same for functional charecterizations of imperative programs,
which requires much more technical sophistication and which you may not normally present to
the novice programmer.
Now let me turn to the (more subjective, less technical) issue of how programmers think
about Id loops. I would make the following analogy. Does the average programmer who uses
MAP and FILTER think in terms of the underlying FOLDR recursion? Does the average
programmer who uses LIST COMPREHENSIONS think in terms of the underlying FLATTENs, MAPs and
FILTERs (or FOLDRs, to get more detailed)? Even though that's how you might have originally
explained these constructs, I don't think the average programmer routinely descends to that
level each time he uses one of them. The same is true with Id loops. The correspondence
with tail recursion is explained first, and once you understand how it works, which is very
easy, you do not routinely think in terms of tail recursion each time you use a loop.
I emphasize that my comments are specific to loops in Id, and not to loops in other
languages. In particular, Id loops are VERY different from Fortran or Pascal loops.
In article <1991Sep20.1...@sics.se>, bjo...@sics.se (Bj|rn Lisper) continues:
> I would put "dataflow" languages somewhere in-between imperative and
> "purely" functional programs.
>
> Bjorn Lisper
I have different viewpoint. To me, "dataflow" is an implementation technique, and is
entirely orthogonal to the functional vs. imperative dimension. Dataflow techniques may be
used to implement functional languages, logic languages or imperative languages (E.g. Id,
ICOT's KL1, and Pingali's FORTRAN, respectively). Dataflow is also orthogonal to the strict
vs. non-strict dimension. But this is another long discussion ...
Best regards,
Nikhil
--
------------------------------------------------------------
NAME: Rishiyur S. Nikhil
EMAIL: nik...@crl.dec.com
------------------------------------------------------------
>> I would put "dataflow" languages somewhere in-between imperative and
>> "purely" functional programs.
>I have different viewpoint. To me, "dataflow" is an implementation
>technique, and is entirely orthogonal to the functional vs. imperative
>dimension. Dataflow techniques may be used to implement functional
>languages, logic languages or imperative languages (E.g. Id, ICOT's KL1, and
>Pingali's FORTRAN, respectively). Dataflow is also orthogonal to the strict
>vs. non-strict dimension. But this is another long discussion ...
I agree. "Dataflow language" is a misnomer, since we're dealing with general
programming languages which could be implemented on any machine. I used the
term only since it is quite commonly agreed upon.
Bjorn Lisper