Declarative programming introduction
"Haskell is a very elegant language, and the functional nature of it makes it a beautiful glue language... because the nature of Haskell as a language can make things clearer than many other programming languages" -- Mark C. Chu-Carroll of the ScienceBlogs
"Haskell is a declarative language in that the program can be treated as a statement of facts, rather than as a set of commands that are sequenced in time" -- cdsmith
Declarative programming is a programming paradigm that encourages that the programming logic describes what the program will do as opposed to how it will do it. Also, you don't define your programming logic in a sequence of steps like you normally would using an imperative style programming. Functional programming is considered declarative programming.
With the imperative programming paradigm, one might do the following to reach a desired state.
In Java (imperative style):
With the code snippet, it would be difficult to reach the send email function without first calling deposit and calling the set owner routines. The program must be initialized before the developer can really start to perform operations on the savings and checking accounts. Already one can see where problems might arise. The developer might be required to establish the owner name or the user needs to have a non zero account balance. Are the account classes instantiated? It really becomes complicated in programs with thousands of classes and hundreds of thousands of lines of code.
With many personal computers, the instructions are processed in a sequence of steps. Here is a program listing for the x86:
The Java Virtual Machine interprets compiled bytecode and executes those instructions. Here is the javap assembly translation of the Java bytecode of the bank account program:
The problem with the imperative paradigm becomes obvious. What happens if the developer doesn't invoke the routines in the right order? Will the program run correctly? Declarative programming, on the other hand, establishes what the program should do. What is required for this program to run correctly? Some parts of HTML are declarative. The HTML syntax describes how parts of the content should appear.
HTML is a not a Turing complete, general purpose programming language, but it does show an example of a declarative syntax. The HEAD tag declares to the browser to process any meta data, JavaScript or CSS include scripts. The BODY tag declares to the browser to process the BODY of HTML content to display to the user. In the example snippet, the FORM tag contains one input box and two submit button tags. When the user clicks on one of the buttons, the browser will send a request to the server, the URL processBankAccount. The server will respond to the request.
This HTML program does everything that it is expected to in order to give the desired state. All of the tags that we want present are present. Most modern browsers will interpret the head, body, form tags and render the form, input box and two buttons. It doesn't even matter if a server is available or not. As I mentioned with imperative programming, programs are processed from top to bottom. With HTML and with the simple example, if the developer declares one body tag, the browser could process the BODY tag before the HEAD and process from bottom to top.
The SQL SELECT statement is also a declarative syntax for returning data from a database. The query includes the list of columns to be included in the result set returned from the database.
This Java programming example is written using a declarative approach. HTML was used as the basis for the example.
Prolog is a programming considered to be declarative and Erlang is a popular general purpose programming influenced by Prolog.
How would the system process the Erlang factorial definition? Declarative programming doesn't necessarily acknowledge a sequence of steps but the declared patterns are relevant. In the Erlang example, the function name is defined as well as an input and input pattern, factorial(0) -> 1;
Here is a verbose Java equivalent of the Erlang example. The 'Erlang copy' is at the top, the bottom portion contains the Java parser.
Summary
For the most part, most popular programming languages are not entirely declarative or imperative. A developer may use an approach that is declarative or imperative in nature using most of the mainstream languages. But there is still no absolute guarantee that declarative programming is free of unexpected behavior. Take a harmless HTML page, let's say you copy-paste an action URL that contains UTF32 encoding in a HTML document that expects UTF8. Will the HTML FORM operate correctly? Or, what if you provide an action URL in your HTML FORM that is too long for the particular browser that the user is working with. The input HTML declaration might be correct but the browser could not parse the document correctly. This brings up one issue with declarative syntax, if the program is correct based on the language specification, it is possible that the magic behind the implementing system is incorrect or not consistent with the specification.
Resources:
http://en.wikipedia.org/wiki/Lambda_calculus
Why Haskell?
"Haskell is a declarative language in that the program can be treated as a statement of facts, rather than as a set of commands that are sequenced in time" -- cdsmith
Declarative programming is a programming paradigm that encourages that the programming logic describes what the program will do as opposed to how it will do it. Also, you don't define your programming logic in a sequence of steps like you normally would using an imperative style programming. Functional programming is considered declarative programming.
With the imperative programming paradigm, one might do the following to reach a desired state.
In Java (imperative style):
final SavingsAccount savings = new SavingsAccount(); // Step1 final CheckingAccount checking = new CheckingAccount(); // Step2 savings.setOwner("Bob Jones"); checking.setOwner("Bob Jones"); savings.deposit(100); checking.deposit(100); savings.withdraw(10); checking.withdraw(10); if ((savings.balance() > 0) || (checkings.balance() > 0)) { sendEmailFromBankYouAreAGreatCustomer(savings, checkings); }
With the code snippet, it would be difficult to reach the send email function without first calling deposit and calling the set owner routines. The program must be initialized before the developer can really start to perform operations on the savings and checking accounts. Already one can see where problems might arise. The developer might be required to establish the owner name or the user needs to have a non zero account balance. Are the account classes instantiated? It really becomes complicated in programs with thousands of classes and hundreds of thousands of lines of code.
With many personal computers, the instructions are processed in a sequence of steps. Here is a program listing for the x86:
mov ah, 09h lea dx, msg int 21h mov ax, 4C00h intProgrammers are more familiar with computational logic that flows from top to bottom, in a sequence of steps because that is the way that many machines process instructions.
The Java Virtual Machine interprets compiled bytecode and executes those instructions. Here is the javap assembly translation of the Java bytecode of the bank account program:
public static void main(java.lang.String[]); Code: Stack=2, Locals=3, Args_size=1 0: getstatic #22; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #28; //String Running 5: invokevirtual #30; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: new #36; //class thepack/ImperativeJavaExample$SavingsAccount 11: dup 12: invokespecial #38; //Method thepack/ImperativeJavaExample$SavingsAccount."":()V 15: astore_1 16: new #39; //class thepack/ImperativeJavaExample$CheckingAccount 19: dup 20: invokespecial #41; //Method thepack/ImperativeJavaExample$CheckingAccount." ":()V 23: astore_2 24: aload_1 25: ldc #42; //String Bob Jones 27: invokevirtual #44; //Method thepack/ImperativeJavaExample$SavingsAccount.setOwner:(Ljava/lang/String;)V 30: aload_2 31: ldc #42; //String Bob Jones 33: invokevirtual #47; //Method thepack/ImperativeJavaExample$CheckingAccount.setOwner:(Ljava/lang/String;)V 36: aload_1 37: bipush 100 39: invokevirtual #48; //Method thepack/ImperativeJavaExample$SavingsAccount.deposit:(I)V 42: aload_2 43: bipush 100 45: invokevirtual #52; //Method thepack/ImperativeJavaExample$CheckingAccount.deposit:(I)V 48: aload_1 49: bipush 10 51: invokevirtual #53; //Method thepack/ImperativeJavaExample$SavingsAccount.withdraw:(I)V 54: aload_2 55: bipush 10 57: invokevirtual #56; //Method thepack/ImperativeJavaExample$CheckingAccount.withdraw:(I)V 60: aload_1 61: invokevirtual #57; //Method thepack/ImperativeJavaExample$SavingsAccount.balance:()I 64: ifgt 74 67: aload_2 68: invokevirtual #61; //Method thepack/ImperativeJavaExample$CheckingAccount.balance:()I 71: ifle 79 74: aload_1 75: aload_2 76: invokestatic #62; //Method sendEmailFromBankYouAreAGreatCustomer:(Lthepack/ImperativeJavaExample$SavingsAccount;Lthepack/ImperativeJavaExample$CheckingAccount;)V 79: getstatic #22; //Field java/lang/System.out:Ljava/io/PrintStream; 82: ldc #64; //String Done 84: invokevirtual #30; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 87: return
The problem with the imperative paradigm becomes obvious. What happens if the developer doesn't invoke the routines in the right order? Will the program run correctly? Declarative programming, on the other hand, establishes what the program should do. What is required for this program to run correctly? Some parts of HTML are declarative. The HTML syntax describes how parts of the content should appear.
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <form action="/processBankAccount"> <input name="amount" /> <input type="submit" value="withdraw" /> <input type="submit" value="deposit" /> </form> </body> </html>
HTML is a not a Turing complete, general purpose programming language, but it does show an example of a declarative syntax. The HEAD tag declares to the browser to process any meta data, JavaScript or CSS include scripts. The BODY tag declares to the browser to process the BODY of HTML content to display to the user. In the example snippet, the FORM tag contains one input box and two submit button tags. When the user clicks on one of the buttons, the browser will send a request to the server, the URL processBankAccount. The server will respond to the request.
This HTML program does everything that it is expected to in order to give the desired state. All of the tags that we want present are present. Most modern browsers will interpret the head, body, form tags and render the form, input box and two buttons. It doesn't even matter if a server is available or not. As I mentioned with imperative programming, programs are processed from top to bottom. With HTML and with the simple example, if the developer declares one body tag, the browser could process the BODY tag before the HEAD and process from bottom to top.
The SQL SELECT statement is also a declarative syntax for returning data from a database. The query includes the list of columns to be included in the result set returned from the database.
SELECT (FIELD1, FIELD2) from TABLE2 where FIELD1 = 3 SELECT [column_parameter_listing] FROM [table_listing] WHERE [clause]
This Java programming example is written using a declarative approach. HTML was used as the basis for the example.
package org.berlin.basic; import java.util.HashMap; import java.util.Map; /** * Declarative Java example based on HTML syntax. This example is intentionally * verbose. */ public class DeclarativeJavaHTMLExample { /** * A HTML TAG declaration type. */ public static interface DeclarativeHtmlTag { public String contentGeneratedByCodeGenerator(); } /** * Syntax validator, ensure that all HTML tags are provided before rendering * content. */ public static interface HtmlSyntaxValidator { public void defineTag(final String tagName, final DeclarativeHtmlTag tag); public boolean validate(); public Map<String, DeclarativeHtmlTag> queryMetaDataTags(); } /** * HTML Browser system, this is the end point for our computations. Process * program and render output to user. */ public static interface BrowerSystemRendererProgram { public String renderAndProcessProgram(); } /** * A program loader type, allow developer to define program HTML tags. */ public static interface ComputationLogicLoader { public DeclarativeMetaDataDescription loadProgramTags( final DeclarativeMetaDataDescription metaDataTargetOfLoad); } /** * A program loader type, allow developer to define program HTML tags. This * class is typically where the developer would add most of his logic. The * order is not important. */ public static class ProgramLogicLoader implements ComputationLogicLoader { public DeclarativeMetaDataDescription loadProgramTags( final DeclarativeMetaDataDescription metaDataTargetOfLoad) { metaDataTargetOfLoad.defineTag("body", new DeclarativeHtmlTag() { public String contentGeneratedByCodeGenerator() { return "<body>DATA</body>"; } }); metaDataTargetOfLoad.defineTag("input", new DeclarativeHtmlTag() { public String contentGeneratedByCodeGenerator() { return "<input><name>account</name></input>"; } }); metaDataTargetOfLoad.defineTag("form", new DeclarativeHtmlTag() { public String contentGeneratedByCodeGenerator() { return "<form><action>/processor</action></form>"; } }); metaDataTargetOfLoad.defineTag("input_submit_withdraw", new DeclarativeHtmlTag() { public String contentGeneratedByCodeGenerator() { return "<input_submit_withdraw>DATA</input_submit_withdraw>"; } }); metaDataTargetOfLoad.defineTag("input_submit_deposit", new DeclarativeHtmlTag() { public String contentGeneratedByCodeGenerator() { return "<input_submit_deposit>DATA</input_submit_deposit>"; } }); metaDataTargetOfLoad.defineTag("head", new DeclarativeHtmlTag() { public String contentGeneratedByCodeGenerator() { return "<head>RENDER_AS_UTF8</head>"; } }); // Oops I want to correct my head tag, added another one metaDataTargetOfLoad.defineTag("head", new DeclarativeHtmlTag() { public String contentGeneratedByCodeGenerator() { return "<head>RENDER_AS_UTF16</head>"; } }); return metaDataTargetOfLoad; } } /** * Syntax validator, ensure that all HTML tags are provided before rendering * content. */ public static class DeclarativeMetaDataDescription implements HtmlSyntaxValidator { private Map<String, DeclarativeHtmlTag> metaDataTags = new HashMap<String, DeclarativeHtmlTag>(); public Map<String, DeclarativeHtmlTag> queryMetaDataTags() { return metaDataTags; } /** * Return true if the data contained in meta-data is valid. */ public boolean validate() { // Verify that there are six tags // head, body, form, input, input_submit_withdraw, input_submit_deposit if (metaDataTags == null) { throw new IllegalStateException( "Invalid Declarative Requirements - no metadata found"); } // Notice, I am not worried about order here: if (metaDataTags.get("input") == null) { throw new IllegalStateException( "Invalid Declarative Requirements - no metadata found, input"); } if (metaDataTags.get("input_submit_withdraw") == null) { throw new IllegalStateException( "Invalid Declarative Requirements - no metadata found, submit withdraw"); } if (metaDataTags.get("input_submit_deposit") == null) { throw new IllegalStateException( "Invalid Declarative Requirements - no metadata found, submit deposit"); } if (metaDataTags.get("body") == null) { throw new IllegalStateException( "Invalid Declarative Requirements - no metadata found, body"); } if (metaDataTags.get("head") == null) { throw new IllegalStateException( "Invalid Declarative Requirements - no metadata found, head"); } if (metaDataTags.get("form") == null) { throw new IllegalStateException( "Invalid Declarative Requirements - no metadata found, form"); } return true; } @Override public void defineTag(final String tagName, final DeclarativeHtmlTag tag) { metaDataTags.put(tagName, tag); } } // End of class /** * HTML Browser system, this is the end point for our computations. Process * program and render output to user. */ public static class BrowserSystemProcessMetaData implements BrowerSystemRendererProgram { private DeclarativeMetaDataDescription declarativeMetaData; public BrowserSystemProcessMetaData( final DeclarativeMetaDataDescription declarativeMetaData) { this.declarativeMetaData = declarativeMetaData; } public String renderAndProcessProgram() { declarativeMetaData.validate(); final StringBuilder buf = new StringBuilder(); // Render in a specific order, this is somewhat imperative // because the user expects the rendered output in a particular order but // that // is a requirement of the browser not the input program code generator. buf.append(this.declarativeMetaData.queryMetaDataTags() .get("head").contentGeneratedByCodeGenerator()); buf.append('\n'); buf.append(this.declarativeMetaData.queryMetaDataTags() .get("body").contentGeneratedByCodeGenerator()); buf.append('\n'); buf.append(this.declarativeMetaData.queryMetaDataTags() .get("form").contentGeneratedByCodeGenerator()); buf.append('\n'); buf.append(this.declarativeMetaData.queryMetaDataTags() .get("input").contentGeneratedByCodeGenerator()); buf.append('\n'); buf.append(this.declarativeMetaData.queryMetaDataTags() .get("input_submit_withdraw") .contentGeneratedByCodeGenerator()); buf.append('\n'); buf.append(this.declarativeMetaData.queryMetaDataTags() .get("input_submit_deposit") .contentGeneratedByCodeGenerator()); buf.append('\n'); return buf.toString(); } } // End of Class // /** * Imperative Java main entry point, run the program. * * @param args */ public static void main(final String[] args) { final DeclarativeMetaDataDescription myCoreProgramDefinition = new DeclarativeMetaDataDescription(); final BrowserSystemProcessMetaData browser = new BrowserSystemProcessMetaData( new ProgramLogicLoader() .loadProgramTags(myCoreProgramDefinition)); System.out.println(browser.renderAndProcessProgram()); } } // End of the Class //
Output from the Java Renderer Program: <head>RENDER_AS_UTF16</head> <body>DATA</body> <form><action>/processor</action></form> <input><name>account</name></input> <input_submit_withdraw>DATA</input_submit_withdraw> <input_submit_deposit>DATA</input_submit_deposit>
Prolog is a programming considered to be declarative and Erlang is a popular general purpose programming influenced by Prolog.
Factorial in prolog: factorial(0,1). factorial(N,F) :- N > 0, N1 is N-1, factorial(N1,F1), F is N * F1. ?- factorial(3,W).
Factorial in Erlang: -module(mathFactorial). -export([factorial/1, area/1]). factorial(0) -> 1; factorial(N) -> N * factorial(N-1). factorial(3)
How would the system process the Erlang factorial definition? Declarative programming doesn't necessarily acknowledge a sequence of steps but the declared patterns are relevant. In the Erlang example, the function name is defined as well as an input and input pattern, factorial(0) -> 1;
Here is a verbose Java equivalent of the Erlang example. The 'Erlang copy' is at the top, the bottom portion contains the Java parser.
package org.berlin.basic; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; /** * Declarative Java example based on Erlang syntax. This example is * intentionally verbose. */ public class DeclarativeJavaToErlangExample { /** * A program loader type, allow developer to define program lines of Erlang * code. */ public static class DefaultErlangComputationLogicLoader implements ErlangComputationLogicLoader { @Override public ErlangProgramMetaData loadProgramTags( final ErlangProgramMetaData metaDataTargetOfLoad) { metaDataTargetOfLoad .defineErlangFunctionDefition("% Program in Erlang") .defineErlangFunctionDefition("% ------") .defineErlangFunctionDefition("FACT 0 -> 1 xxxxxxxxxxxx") .defineErlangFunctionDefition("FACT 1 -> 1 xxxxxxxxxxxx") .defineErlangFunctionDefition("FACT 2 -> 2 xxxxxxxxxxxx") .defineErlangFunctionDefition("FACT 3 -> 6 xxxxxxxxxxxx") .defineErlangFunctionDefition("FACT 4 -> 24 xxxxxxxxxxx") .defineErlangFunctionDefition("FACT 5 -> 120 xxxxxxxxxx") .defineErlangFunctionDefition("% Run the program") .defineErlangFunctionDefition("FACT 5"); return metaDataTargetOfLoad; } } /** * A Line declaration type. */ public static interface DeclarativeErlangLine { public String queryErlangLineFunctionName(); public String queryErlangLineInputPattern(); public String queryErlangLineOutputPattern(); public int queryErlangLineNumber(); } /** * Program container */ public static interface ErlangProgramMetaData { public ErlangProgramMetaData defineErlangFunctionDefition( final String declarativeErlangLineOfCode); public List<DeclarativeErlangLine> queryLinesOfCode(); } /** * A program loader type, allow developer to define program lines of Erlang * code. */ public static interface ErlangComputationLogicLoader { public ErlangProgramMetaData loadProgramTags( final ErlangProgramMetaData metaDataTargetOfLoad); } /** * Erlang parser system, this is the end point for our computations. Process * program and render output to user. */ public static interface ErlangSystemParserProgram { public String parseAndProcessProgram(); } public static class ErlangProgram implements ErlangProgramMetaData { private final List<String> rawInputErlangProgram = new ArrayList<String>(); private final List<DeclarativeErlangLine> validLinesOfCode = new ArrayList<DeclarativeErlangLine>(); private int lineNumber = 0; public ErlangProgramMetaData defineErlangFunctionDefition( final String declarativeErlangLineOfCodeRawIn) { final String declarativeErlangLineOfCodeRaw = declarativeErlangLineOfCodeRawIn; // Perform parsing of the input, if valid // add to query lines. lineNumber++; if (declarativeErlangLineOfCodeRaw == null || (declarativeErlangLineOfCodeRaw.trim().length() == 0)) { // ignore whitespace return this; } if (declarativeErlangLineOfCodeRaw.startsWith("%")) { return this; } rawInputErlangProgram.add(declarativeErlangLineOfCodeRaw); // FACT 0 -> 1 xxxxxxxxxxxx // FACT _ -> N * FACT N - 1 // FACT 3 if (declarativeErlangLineOfCodeRaw.length() != 24 && declarativeErlangLineOfCodeRaw.length() != 6) { throw new IllegalStateException("Parser Exception on Line:" + lineNumber + ", invalid line length(expecting 24), invalidLen=" + declarativeErlangLineOfCodeRaw.length()); } if (declarativeErlangLineOfCodeRaw.length() == 6) { // Run program final int resLineNumber = lineNumber; validLinesOfCode.add(new DeclarativeErlangLine() { public String queryErlangLineFunctionName() { return declarativeErlangLineOfCodeRaw.toUpperCase() .substring(0, 4); } public String queryErlangLineInputPattern() { return declarativeErlangLineOfCodeRaw.toUpperCase() .substring(5, 6); } public String queryErlangLineOutputPattern() { return null; } public int queryErlangLineNumber() { return resLineNumber; } }); return this; } // For the output, we don't care, just extract the last part validLinesOfCode.add(new DeclarativeErlangLine() { final int resLineNumber = lineNumber; public String queryErlangLineFunctionName() { return declarativeErlangLineOfCodeRaw.toUpperCase() .substring(0, 4); } public String queryErlangLineInputPattern() { return declarativeErlangLineOfCodeRaw.toUpperCase() .substring(5, 6); } public String queryErlangLineOutputPattern() { return declarativeErlangLineOfCodeRaw.toUpperCase() .substring(8); } public int queryErlangLineNumber() { return resLineNumber; } }); return this; } @Override public List<DeclarativeErlangLine> queryLinesOfCode() { return validLinesOfCode; } } public static class DefaultErlangSystemParserProgram implements ErlangSystemParserProgram { private ErlangProgramMetaData declarativeProgramMetaData; public DefaultErlangSystemParserProgram( final ErlangProgramMetaData declarativeMetaData) { this.declarativeProgramMetaData = declarativeMetaData; } /** * Parse the developer created data program. */ public String parseAndProcessProgram() { // parser designed for factorial final Map<String, DeclarativeErlangLine> program = new HashMap<String, DeclarativeErlangLine>(); final Stack<DeclarativeErlangLine> runLineCache = new Stack<DeclarativeErlangLine>(); final class AllowForRecursiveFunc { public int lookupAndParse(final String function, final String input) { // try to find function and input final int inval = Integer.parseInt(input); final String lookupKeyCheck = "[" + function.toUpperCase() + " " + input + "]"; final String lookupKeyCheckForOne = "[" + function.toUpperCase() + " 1]"; if (inval <= 0) { final DeclarativeErlangLine processLineRunLookup = program .get(lookupKeyCheckForOne); System.out .println("*SYS-OUT* {reached min input} pattern-match output = " + processLineRunLookup .queryErlangLineOutputPattern() + " matches N = " + inval + " at line " + processLineRunLookup.queryErlangLineNumber()); return 1; } else { final DeclarativeErlangLine processLineRunLookup = program .get(lookupKeyCheck); if (processLineRunLookup != null) { System.out.println("*SYS-OUT* pattern-match output = " + processLineRunLookup .queryErlangLineOutputPattern() + " matches N = " + inval + " at line " + processLineRunLookup.queryErlangLineNumber()); final int lastInput = lookupAndParse(function, String.valueOf(inval - 1)); return lastInput; } } return inval; } } // End of class for (final DeclarativeErlangLine erlang : declarativeProgramMetaData .queryLinesOfCode()) { final String key = "[" + erlang.queryErlangLineFunctionName() + " " + erlang.queryErlangLineInputPattern() + "]"; if (erlang.queryErlangLineOutputPattern() == null) { // Execute line runLineCache.push(erlang); } else { program.put(key, erlang); } } // Run the run line caches while (!runLineCache.isEmpty()) { final DeclarativeErlangLine processLineRunLookup = runLineCache .pop(); System.out.println("*SYS-OUT* Parsing runLine : function=" + processLineRunLookup.queryErlangLineFunctionName() + " inputParm=" + processLineRunLookup.queryErlangLineInputPattern()); new AllowForRecursiveFunc().lookupAndParse( processLineRunLookup.queryErlangLineFunctionName(), processLineRunLookup.queryErlangLineInputPattern()); } return ""; } } /** * Imperative Java main entry point, run the program. * * @param args */ public static void main(final String[] args) { final ErlangProgramMetaData myCoreProgramDefinition = new ErlangProgram(); System.out.println(new DefaultErlangSystemParserProgram( new DefaultErlangComputationLogicLoader() .loadProgramTags(myCoreProgramDefinition)) .parseAndProcessProgram()); } } // End of class //
Output from the Factorial Erlang Java Application: *SYS-OUT* Parsing runLine : function=FACT inputParm=5 *SYS-OUT* pattern-match output = > 120 XXXXXXXXXX matches N = 5 at line 8 *SYS-OUT* pattern-match output = > 24 XXXXXXXXXXX matches N = 4 at line 7 *SYS-OUT* pattern-match output = > 6 XXXXXXXXXXXX matches N = 3 at line 6 *SYS-OUT* pattern-match output = > 2 XXXXXXXXXXXX matches N = 2 at line 5 *SYS-OUT* pattern-match output = > 1 XXXXXXXXXXXX matches N = 1 at line 4 *SYS-OUT* {reached min input} pattern-match output = > 1 XXXXXXXXXXXX matches N = 0 at line 4
Summary
For the most part, most popular programming languages are not entirely declarative or imperative. A developer may use an approach that is declarative or imperative in nature using most of the mainstream languages. But there is still no absolute guarantee that declarative programming is free of unexpected behavior. Take a harmless HTML page, let's say you copy-paste an action URL that contains UTF32 encoding in a HTML document that expects UTF8. Will the HTML FORM operate correctly? Or, what if you provide an action URL in your HTML FORM that is too long for the particular browser that the user is working with. The input HTML declaration might be correct but the browser could not parse the document correctly. This brings up one issue with declarative syntax, if the program is correct based on the language specification, it is possible that the magic behind the implementing system is incorrect or not consistent with the specification.
Resources:
http://en.wikipedia.org/wiki/Lambda_calculus
Why Haskell?
Comments