imports
{-# LANGUAGE OverloadedStrings #-}
module Plutarch.Docs.PlutarchLambdas (pid, pid') where
import Plutarch.Prelude
Lambdas are the second form of Plutarch Term
s. Lambda terms are represented at the type level by the infix type constructor :-->
; a value of type Term s (a :--> b)
evaluates to a function that takes a value of type a
and produces a value of type b
.
You can create Plutarch lambda Term
s by applying the plam
function to a Haskell-level function that works on Plutarch terms. The true type of plam
itself is unimportant to end-users of Plutarch, but it should be thought of as
plam :: (Term s a -> Term s b) -> Term s (a :--> b)
To create the identity function as a Plutarch lambda, we would thus use:
-- | Haskell-level `id` function specialized to the `Term s a` type``
termId :: Term s a -> Term s a
termId x = x
-- | Plutarch-level `id` lambda
pid :: Term s (a :--> a)
pid = plam termId
-- | Equivalently:
pid' :: Term s (a :--> a)
pid' = plam $ \x -> x
Notice the type. A Plutarch lambda Term
uses the :-->
infix operator to encode a function type. So in the above case, pid
is a Plutarch level function that takes a type a
and returns the same type. As one would expect, :-->
is right-associative, and things curry like a charm.
Guess what this Plutarch level function does:
f :: Term s (PInteger :--> PString :--> a :--> a)
It takes in an integer, a string, and a type a
and returns the same type a
. Notice that the types are all of kind PType
. This means that when faced with filling out the gap:
f :: Term s (PInteger :--> PString :--> a :--> a)
f = plam $ \???
We know that the argument to plam
here is a Haskell function g
with type Term s PInteger -> Term s PString -> Term s a -> Term s a
.
Function Application
Once we construct a Plutarch lambda Term
using plam
, it is rather useless unless we apply it to an argument. Plutarch provides two operators to do so
{- |
High precedence infixl function application, to be used like
function juxtaposition. e.g.:
>>> f # x # y
Conceptually: f x y
-}
(#) :: Term s (a :--> b) -> Term s a -> Term s b
infixl 8 #
{- |
Low precedence infixr function application, to be used like
`$`, in combination with `#`. e.g.:
>>> f # x #$ g # y # z
Conceptually: f x (g y z)
-}
(#$) :: Term s (a :--> b) -> Term s a -> Term s b
infixr 0 #$
The types of each operator match our intuition. Applying a lambda Term
to a Term
(tagged with the PType
of the domain of the lambda) produces a Term
(tagged with the PType
of the codomain.).