Programming Language Design

Various ideas on the design of programming languages

Featured image of post Functional Equality: When 2+2 does not equal 4.0

Functional Equality: When 2+2 does not equal 4.0

Introduction In this essay, I introduce the concept of functional equality, and discuss why 2+2 may or may not equal 4.0. Obviously 2+2 is mathematically equal to 4.0. And yet in many programming languages, the integer and float representations of the same number are functionally different values, because operations such as division and conversion-to-string behave differently for different types. When comparing two values for equality, it is important to ask, what do you mean by “equal”?
Featured image of post Pass-Through Lists

Pass-Through Lists

The pass-through list is a programming-language feature intended to make it easier for programmers to modify functions to return additional values without breaking backwards compatibility, in the same way it is easy to modify functions to take additional parameters without breaking backwards compatibility. This is done by, in a sense, unifying the semantics of passing parameters to functions and returning values from functions. Problem Suppose I have an inverse function that takes one number and returns one number, in some hypothetical untyped language:
Featured image of post Effects without Side-Effects

Effects without Side-Effects

Part of the Procedures in a Pure Language series

In my post on Procedures in a Pure Language, I discuss how even pure functional languages can be used to create procedures that have effects, and how that is how things should be. I propose a little language where these impure procedures can coexist with pure functions in a way that makes the line between pure and impure very clear. In this post, I propose adding a stricture to this language that ensures that, while procedures can have effects, they cannot have side-effects.
Featured image of post Procedures in a Pure Language

Procedures in a Pure Language

Part of the Procedures in a Pure Language series

The Problem The fact that you can write procedures, which produce side-effects, in Haskell, which is supposed to be a pure language, can be confusing. I think the key to clearing up the confusion is to understand that most Haskell programs are actually programs that produce programs – like preprocessors in CPP. Conal Elliott’s post The C language is purely functional explores this idea. The Haskell language itself is pure. When evaluated, Haskell expressions have no side effects, and are referentially transparent.
Featured image of post Functional Environment Variables

Functional Environment Variables

Global environment variables violate a core principle of functional programming. For example, this is not very acceptable in the FP world: def hello = if(locale == 'en.US') "hello" elsif(locale == 'fr.FR') "bonjour" locale shouldn’t just be there as a global. In an pure functional language it should be passed as a parameter, according to the the principle of referential transparency. def hello(locale) = if(locale == 'en.US') "hello" elsif(locale == 'fr.FR') "bonjour" But this means you also have to pass locale to every function that calls hello.
Featured image of post Functional Dependency Injection

Functional Dependency Injection

In this post I’ll talk about dependency injection and IoC in functional programming languages, and propose a solution for achieving IoC with given/inject preprocessing. The terms Dependency Injection and Inversion of Control tend to be used in OOP circles, though these concepts are applicable to virtually any language. Dependency Injection for Dummies A good summary of the definitions of these concepts is the first answer by Garret Hall on the stack overflow question Inversion of Control vs Dependency Injection.
Featured image of post Implicit Currying and Folded Application

Implicit Currying and Folded Application

Implicit currying and folded application are language feature that render moot the distinction between curried and un-curried functions, allowing functions written in curried style to be called as un-curried functions and vice-versa. Quick Background: Currying Currying is the technique of translating a function that takes multiple arguments, or a tuple of arguments (an n-ary function) into a sequence of functions, each with a single argument. For example: // binary function (uncurried form) let product = (x,y) -> x*y // curried form of same function let product = x -> y -> x*y The curried form of the function has to be invoked differently than the uncurried form:
Featured image of post Self-Evaluating Data

Self-Evaluating Data

The Problem Why were keywords and vectors added to LISP, a language that was already based on symbols and lists? The answer: because keywords and vectors are self-evaluating. The expression :foo evaluates to :foo. The expression [1,2] evaluate to [1,2]. Like string and number literals, they are what they are. Unlike symbols and lists, they are never treated as code that is replaced with some other value when evaluated. You might argue that if you don’t want to symbol or a list to be treated as code, just don’t evaluate it!
Featured image of post Generic Syntax

Generic Syntax

Is it really necessary to invent a new syntax, complete with a new grammar and parser, for every new programming language? Is there a generic syntax that can conveniently express the semantics of many languages? Since all languages, whatever the syntax, are eventually parsed into an abstract syntax tree, couldn’t we just use a general language for expressing abstract syntax trees? XML and LISP XML was designed to be generic enough to express data and concepts from virtually any domain.