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):
 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
 int
Programmers 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 "&lt;body&gt;DATA&lt;/body&gt;";
            }
          });
      metaDataTargetOfLoad.defineTag("input",
          new DeclarativeHtmlTag() {
            public String contentGeneratedByCodeGenerator() {
              return "&lt;input&gt;&lt;name&gt;account&lt;/name&gt;&lt;/input&gt;";
            }
          });
      metaDataTargetOfLoad.defineTag("form",
          new DeclarativeHtmlTag() {
            public String contentGeneratedByCodeGenerator() {
              return "&lt;form&gt;&lt;action&gt;/processor&lt;/action&gt;&lt;/form&gt;";
            }
          });
      metaDataTargetOfLoad.defineTag("input_submit_withdraw",
          new DeclarativeHtmlTag() {
            public String contentGeneratedByCodeGenerator() {
              return "&lt;input_submit_withdraw&gt;DATA&lt;/input_submit_withdraw&gt;";
            }
          });
      metaDataTargetOfLoad.defineTag("input_submit_deposit",
          new DeclarativeHtmlTag() {
            public String contentGeneratedByCodeGenerator() {
              return "&lt;input_submit_deposit&gt;DATA&lt;/input_submit_deposit&gt;";
            }
          });
      metaDataTargetOfLoad.defineTag("head",
          new DeclarativeHtmlTag() {
            public String contentGeneratedByCodeGenerator() {
              return "&lt;head&gt;RENDER_AS_UTF8&lt;/head&gt;";
            }
          });
      // Oops I want to correct my head tag, added another one      metaDataTargetOfLoad.defineTag("head",
          new DeclarativeHtmlTag() {
            public String contentGeneratedByCodeGenerator() {
              return "&lt;head&gt;RENDER_AS_UTF16&lt;/head&gt;";
            }
          });
      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

Popular posts from this blog

Is Java the new COBOL? Yes. What does that mean, exactly? (Part 1)

On Unit Testing, Java TDD for developers to write

JVM Notebook: Basic Clojure, Java and JVM Language performance