Procedure With No Arguments

A technical answer to the question "WhatIsaThunk?" 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 SomeClass::ThunkMethod( void );

because ThunkMethod has access to the member variables of SomeClass? (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 FunctionalProgrammingLanguages, thunks generally break the whole functional paradigm because functions aren't supposed to have side effects. However, in the SchemeLanguage/LispLanguage/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. -- SunirShah

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 LazyEvaluation in languages that don't provide it natively. -- StephanHouben


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

This is not compatible with FunctionalProgramming, 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 FunctionalProgramming. -- DanBarlow


In CommonLisp, thunks are often closures which are used as CallBacks?. 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).

-- AlainPicard


In the OcamlLanguage (and other MlLanguage) type system, every "function" has exactly one argument (functions with multiple arguments are curried (CurryingSchonfinkelling) 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 StrictLanguage). 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 HaskellLanguage, the above is not an issue, because Haskell is PurelyFunctional, so there is no point in having a regular function of no arguments (it would be equivalent to a constant because of ReferentialTransparency). Computations with SideEffect are abstracted in Haskell as values called OnMonads (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 IdealProgrammingLanguage 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 (ExplicitManagementOfImplicitContext) and continuation (ContinuationPassingStyle).) 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 IdealProgrammingLanguage 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 ComponentObjectModel, you use thunks to couple C++ to, e.g., VisualBasic. Or, in AmigaOs, 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 HaskellLanguage you could use the special monad syntax to hide the explicit passing of the goodWorld.


EditText of this page (last edited November 3, 2008) or FindPage with title or text search