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 post, I discuss the concept of functional equality. If two values $a$ and $b$ are functionally equal, then there should exist no function $f$ for which $f(a)$ does not equal $f(b)$. For mathematically-minded readers, we can give a more precise definition: $$ a = b ⟺ ∀f ~ f(a) = f(b) $$ In many programming languages, the == operator does not test for functional equality. For example, the integer 4 and the float 4.
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:

Representationless Types

TODO “precisionless” numbers Summary In my essay on functional equality, I discuss situations where there are multiple representations of the same underlying value. I suggest that language and library designers might define representationless types for situations where there are multiple ways of representing the same underlying value. For example, a UniversalTime type without a timezone would be different from the LocalTime type with a timezone. Because they are different types, a UniversalTime value could not be compared to a LocalTime value, even if the timezone of the LocalTime value happened to be GMT.
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.