Procedure With No Arguments

A technical answer to the question "What Isa Thunk?" is that it is a procedure that has no arguments. It is a function with no parameters and no return value.


A thunk is a procedure with no arguments.

That is, a thunk is a subroutine with no arguments and no return value. In C, this would look like:

void Thunk( void );

It's arguable whether or not this is a thunk:

void Some''''''Class::Thunk''''''Method( void );

because ThunkMethod has access to the member variables of Some Class (if it isn't a static method). However, Thunk, above, also has access to global variables.

Thunks are used primarily for their side effects. They are called like so:

Thunk(); anInstance.ThunkMethod();

In Functional Programming Languages, thunks generally break the whole functional paradigm because functions aren't supposed to have side effects. However, in the Scheme Language/Lisp Language/etc. they are sometimes used for either program output or for set! side effects. Note: program output violates the functional paradigm too because it has temporal context (i.e. one line is displayed after another).

That's my best effort. Any comments, folks? Especially on method thunks. -- Sunir Shah

If you use "thunk" in the Scheme sense, then it is a function that returns no arguments but does return a value. A thunk is used to fake Lazy Evaluation in languages that don't provide it natively. -- Stephan Houben


In other words, it's a function that's "called for its side effects."

This is not compatible with Functional Programming, and may be a bad idea if done carelessly. If you see lots of these, someone is probably using too many global variables.


If the thunk is defined inside another function and closes over some of its parent's variables, it may do useful things without involving global variables. I agree that this is still not Functional Programming. -- Dan Barlow


In Common Lisp, thunks are often closures which are used as Call Backs. Thus, one will write

(register-with-some-server #'(lambda () ; no args -- a thunk (foo my-lexical-variable-some-time-later)))

and the thunk will be called by some server when some condition occurs at some point in the future (when foo needs to be called, presumably).


In the Ocaml Language (and other Ml Language) type system, every "function" has exactly one argument (functions with multiple arguments are curried (Currying Schonfinkelling) into functions with one argument that return a function, etc.). If you don't specify any arguments, according to the syntax you would be defining a constant, whose body is to be evaluated immediately (since ML is a Strict Language). Since the purpose of a function of no arguments is typically to perform side effects, you (1) might not want to evaluate it immediately, and (2) might want to evaluate it more than once. So when we need something like a function with no arguments, we give it an argument of type unit, written as "()", the empty tuple, which is like void in C -- a type which carries no information.

In Haskell Language, the above is not an issue, because Haskell is Purely Functional, so there is no point in having a regular function of no arguments (it would be equivalent to a constant because of Referential Transparency). Computations with Side Effect are abstracted in Haskell as values called On Monads (the IO and other monads), and so are not performed directly anyway. You can join computations together in the exact order you want, and you can join the same computation multiple times. So instead of a function of no arguments, you would typically instead define a value, which is typed in the IO monad, and the value would equal a joining together of of the computations that you want to do in the function, either with the (>>=) join operator, or with the "do" notation. One example of this is the "main function" in a Haskell program, which is declared like "main :: IO ()"; i.e. "main" is a value that represents a computation that returns "()" (nothing).

Personally, I think that the Ideal Programming Language would enforce this: there is no such thing as "a procedure with arguments"; instead there are referentially transparent functions that take arguments and return procedures. Any procedure, having no arguments, can be executed any number of times. (However, a procedure might still have a few implicit arguments such as context (Explicit Management Of Implicit Context) and continuation (Continuation Passing Style).) The procedure itself might be a data object subject to analysis; the use of the Haskell IO monad is rather distasteful IMO due to the difficulty involved in decomposing or recomposing the resulting monad structure.

You claim that Haskell IO monads (and, presumably by extension, all monads) are distasteful for various compositional reasons; then, you advocate a system which is precisely what monads in Haskell actually do right now.

I stated 'decomposition', not 'composition'. Haskell provides no support for decomposing functions and thus treating them as "data objects subject to analysis". Some monads are subject to decomposition, but each one requires a specialized set of operators and thus decomposition support cannot be centralized to any one library: one would have great difficulty with, say, generalized serialization or persisting these monad structures to run them later on different machines, or providing tools that can analyze a procedure and tell you about its properties. What I proposed in relation to the comment disparaging Haskell (that the procedure itself be a data object - and not just any data object, but a data object subject to analysis) would require that the data object be standard such that it can be analyzed by a common set of tools... which would allow it to be decomposed, recomposed, serialized, persisted, loaded, etc. Beyond a few other significant and relevant differences that derive from having procedures be analyzable data objects (e.g. 'standardized' support for exceptions and STM and concurrency and workflows and implicit context... rather than whatever the programmer dreams up), I do agree that the Ideal Programming Language I described has a great deal in common with what Haskell does right now. If you're abstracting enough that what I said looks precisely the same as Haskell monads, I imagine it will be very difficult to see the relevant differences.


This is the first time I've heard of this definition (parameterless, valueless procedure). The only definition I've ever been exposed to over the years is of a procedure whose purpose is to couple one language's calling conventions to another. For example, in Component Object Model, you use thunks to couple C++ to, e.g., Visual Basic. Or, in Amiga Os, you use what it called stubs to couple C into the ABI model for calling generic library procedures, like so:

XREF myLibraryBase XDEF _someLibraryProcedure _someLibraryProcedure: move.l a6,-(a7) move.l myLibraryBase,a6

move.l 8(a7),d0 move.l 12(a7),d1 move.l 16(a7),a0 move.l 20(a7),a1 jsr _LVOsomeLibraryProcedure(a6) move.l (a7)+,a6 rts


How is this officially implemented in "proper" FP?:

destroyWorld();

Would it be:

brokenWorld = destroy(goodWorld);

?

Yes. Of course, within Haskell Language you could use the special monad syntax to hide the explicit passing of the goodWorld.

See original on c2.com