What are Proxies in Purescript?

Saravanan M
Nerd For Tech
Published in
3 min readAug 19, 2022

Have you ever been in a situation where you want to pass a type instead of Value or are you confused by what I just said? Let me explain.

Photo by Abolfazl Ranjbar on Unsplash

Let’s first understand, whats the difference between type and value.

myFavoriteNumber :: Int
myFavoriteNumber = 3
myName :: String
myName = "Saravanan"
newtype Email = Email String

myEmail :: Email
myEmail = Email "saravanan.m@gmail.com"

Here all the things that appears after `::` are called types and the things that appears on the left are called values.

If you consider myFavoriteNumber , 3 is the value and Int is the type.

We always pass values to a function, what a function could do if we plainly pass Int to it, instead of specifying its value? (Add two Integers, what is the output?)

Is there any place where we want to pass the type instead of Value? Is it even possible? Yes it is possible and useful in many scenarios.

I hope all of you are familiar with the type class Bounded which has two values top and bottom which give the highest and lowest value respectively of the respective type in which it is defined. (not a big deal if you don’t know, just continue reading)

Consider you want to create a function that prints the lowest and highest possible value of a particular type

getRange :: forall a. Bounded a => {lowest :: a , highest :: a }
getRange = { lowest : bottom
, highest : top
}

But this won’t work, why? How the compiler can decide which top, bottom we want..? Do we want the top of String or Int or any other type? How could we specify the type here?

we could do something like,

getRange :: forall a.(Bounded a) => a -> {lowest :: a,highest :: a }
getRange _ = { lowest : bottom
, highest : top
}

and we can call this function like

>>> getRange 1
{lowest: -2147483648, highest: 2147483647 }

>>> getRange false
{lowest: false, highest: true }

>>> getRange 1.0

Now the purescript compiler knows which top , bottom we want.

But passing a value doesn’t make sense here, we aren’t even using the value. So why are we passing a value like 1, false, 1.0here?

Can we pass only the type Int , Boolean , Number ?

Yes, we can, that’s exactly what Proxies are for. Let’s look at the definition of Proxy

data Proxy a = Proxy

Proxy has only one Constructor(Proxy) which has no arguments, the interesting part is the a which is on the left side, with that a (called phantom types) we can encode the type information.

What exactly do I mean by encode here?

Proxy will act as a Type Holder, you can encode (hold) a type within it, look at the below example

_intProxy :: Proxy Int
_intProxy = Proxy
_numberProxy :: Proxy Number
_numberProxy = Proxy

Here the value of both _intProxy and _numberProxy are same (Proxy) (yes, they are actually useless)

The interesting part is their type.

Their types differ in a very subtle way (Proxy <type>) here the <type> helps in carrying the extra type information.

For _intProxy its Int for _numerProxy its Number

So how could we use the encoded type information in the above example?

In the above function getRange, instead of passing a, we can pass Proxy a

getRange :: forall a. (Bounded a) 
-> Proxy a
=> {lowest :: a , highest :: a }
getRange _ = { lowest : bottom
, highest : top
}

Now you can do something like

>>> getRange _intProxy 
{lowest: -2147483648, highest: 2147483647 }
>>> getRange (Proxy :: Proxy Boolean)-- boolean proxy defined inline
{lowest: false, highest: true }
>>> getRange 1.0 
{ lowest: -Infinity, highest: -Infinity }

Note: We have to explicitly specify the type for Proxies to indicate what's the type of a in the Proxy is.

Proxies are nothing but a way to pass around type information, they are used extensively in places where the type information is enough to take a decision, like type class instance selection.

There are other kind of Proxies like SProxy (which captures Symbol), RLProxy(which is used for Row types) etc. But those are deprecated and so knowing Proxy is enough😉

--

--

Saravanan M
Nerd For Tech

Writes about Functional Programming, Web Development...