papp

Lambdas and functions in general in plu-ts are often just constants seen from the typescript world, however we usually know that what we have is more than just a constant and that it can take arguments.

For this particular reason we have the papp function (which stands for "plu-ts applicaiton")and all it does is tell Typescript that we want to apply one term to another, or in other words pass an argument to a function.

The type signature of papp is something like:

function papp<Input extends PType, Output extends PType>( a: Term<PLam<Input,Output>>, b: Term<Input> ): Term<Output>

as we'll see in the next section, functions can be partially applied so, to preserve this behaviour, papp only takes two arguments:

  1. the function we want to pass the argument to
  2. the argument

then it checks the types are matching, evaluates the argument and applies the result of the evaluation and finally returns the result.

the "$" method

However, having to use an external function in order to pass arguments tends to make the code hard to read.

Here is an example of code if all we had was papp:

papp(
    papp(
        pTwoIntegersList,
        pInt(42)
    ),
    pInt(69)
);

For this reason, often you'll encounter Terms that have a type that looks like this:

type LambdaWithApply =
    Term<PLam<SomeInput, SomeOutput>> // this is our usual type
    & { // extended with some functionalities
        $: ( input: Term<SomeInput> ) => Term<SomeOutput>
    }

where the $ method definition is often nothing more than:

myTerm["$"] = ( someInput: Term<SomeInput> ) => papp( myTerm, someInput );

At first glance, this seems like it does nothing fancy, but it allows us to transform the previous code in something more readable like:

pTwoIntegersList.$( pInt(42) ).$( pInt(69) )