FPTs: Pure Fungibility on the Blockchain

You may have heard a lot about NFT speculative mania in the news and how people are shelling out millions of dollars of monopoly money for digitally signed URLs. And I too initially thought this was an absurd farce and that the emperor was running around with no clothes, up until I realised a way I could personally profit from it, and then it all made perfect sense. It’s time to lean into the crypto grift but with purity.

The key idea of this functional pearl is based on the simple notion that we shouldn’t be trading URLs to Nyan Cat GIFs for millions of dollars, but instead we should be trading pointers to functions for billions of dollars!

Now say you wanted to do some super complex logic, like printing to stdout. Normally we would perform the arcane dark category theory rites and summon the IO monad from the nameless void with the following incantation:

main :: IO ()
main = print "Hello World"

Now this works just fine, but it has a serious problem. It doesn’t involve blockchain. Let’s fix that:

import Control.Monad.Fpt

helloWorld :: FPT '[IO] ()
helloWorld = bid $ 100000 (print "Hello World")

There we go, now this this function involves a monadic wrapper which encodes what we call an FPT (Functional Programming Token) represented at the type level. It is a higher kinded type that wraps a type-level list of effects of the functions we wish to bid on for evaluation. In this case we’re bidding $100,000 for the exclusive rights to print “Hello World” to the screen. This is probably too low an ask, but it’s just an example.

Now instead of just evaluating the IO function directly, we want to evaluate it exclusively using the paradigm-shifting power of the blockchain to write to stdout. We do this by providing our bitcoin private key in the first argument to the runFpt function which evaluates the auction monad to bid on the evaluation of the function we wrote.

main :: IO (Either MoarMoney ())
main = runFpt privKey $ embedToFinal @IO helloWorld
  where
    privKey = "$PRIVATEKEYHERE"

This function will run for about 32 hours while your transaction propagates through the bitcoin mempool, then through a bunch of coal-guzzling server farms in Xinjiang. This ultimately burns through an acre of rainforest in the Amazon, but we can ignore that because it’s an unobservable side effect. If the market is good it will eventually evaluate and yield a response. The result is wrapped in a Either value where the right success value will contain the result of your function or a left failure value in the case where you’ve been outbid. If you’ve been outbid, you’ll simply have to bid higher to evaluate your code because that’s how code under capitalism works.

Many people claim that lazy evaluation is actually a misfeature. Au contraire, consider the real world application of computing the nth Fibonacci number. Since every call to fib will cost us upwards of tens of thousands of dollars (depending on rapidly fluctuating exchange rates) we want to minimize the evaluation of unnecessary calls to the market. With FPTs we’ve finally found the only killer application of laziness: not draining our bank account with useless computation.

fib :: FPT '[IO] ()
fib 0 = pure 0
fib 1 = pure 1
fib n = liftM (+) (fib (n-1)) (fib (n-2))

In the brave new frontier of cryptocurrency our business logic will probably involve some combination of money laundering, ransomware, securities fraud, puppy smashing and IO. It’s important to note that effects aren’t necessarily commutative, we don’t necessarily want to smash the puppies before we launder money, but we can do securities fraud and launder money commutatively. And we’ll probably end up adding a logging interface after-the-fact if our budget affords that level of luxury.

To facilitate with money laundering there is a set of wrappers provided by Control.Monad.WireFraud module which provides a high-level streaming interface for cleaning money tied to crime in a space-efficient way. Simply chain together a bunch of sources and sinks using the launder combinator, which will compose the dirty funds through a series of seemingly legit business and the output will be squeaky clean and run in constant memory.

import Control.Monad.WireFraud

launder :: DodgySource m o -> LegitSink i

Using the effect system of FPT we can magically combine all of this business logic together locally into a single token and then put it up for auction.

cryptoBusinessLogic :: FPT '[IO, Puppy, LaunderMoney] ()
cryptoBusinessLogic = bid $ 10000000 $ do
  profits <- runRansomware
  launderMoney profits drugCartels
  void $ smashPuppies

As with NFTs this token can itself become a laundering instrument, so an FPT can become a higher-order money laundering token in which we launder money through money laundering, just like we do with higher order functions. This “Internet Computer” is vastly more advanced than just shuffling art for organized crime around in a freeport in Switzerland.

Perhaps it’s a valid criticism that functional programmers aren’t concerned with the side effects of their work, and fair enough … only time will tell on that. But at the very least we should be able to use the type system to abstractly model the harm we do to the world at a more granular level using advanced type system features. Because at the end of the day purity and fancy types are what really matters.

The FPT token presale starts next week. To the moon. 💎🙌🚀