brandonchinn178 mentioned some great changes. The first was to do away with `PlanetStat`

and replace it with functions that pulled out the necessary data when given a Planet:

You mentioned Java having a “mapping for free”. In Haskell, you can also get mappings for free with functions; after all, functions are maps from inputs to outputs

```
radius :: Planet -> Radius
radius Mercury = ...
radius ... = ...
mass :: Planet -> Mass
mass Mercury = ...
mass ... = ...
```

This gets rid of the need for the PlanetStat data type, which I think is better, but wouldnt be good if eventually, you want to load the stats from a JSON file (for example)

This is more idiotmatic Haskell. The only down side is that you don’t pull out all the information you need at the same time and have to write two functions in this case.

He also mentioned a few other changes:

you dont need type annotations for minBound/maxBound, since you have the final result typed as [Planet]

This is true and an easy fix.

```
planetValues :: [Planet]
planetValues = [minBound .. maxBound]
```

I personally wouldnt have a newtype for literally every single function output. I would say its fine to just return a Double for surface gravity / weight

I erred on the side of “readability” for this one, but adding in a lot of newtypes does add noise.

“massOnEarth” is misleading: its the mass regardless of what planet youre on

I am not so sure about this one. From the Java example it does seem like the mass supplied is the one on Earth which is then compared to its mass on other planets.

instead of traversing a simple putStrLn over a formatted list of strings, I would defer the string rendering as much as possible, e.g.

```
let planetToWeight = map (\p -> (p, surfaceWeight massOnEarth p)) [minBound .. maxBound]
render (p, weight) = "Your weight on " <> show p <> ...
in mapM_ (putStrLn . render) planetToWeight
```

I’ve always found Haskell’s String concatenation/interpolation a bit clunky so I’ve taken to separating the String generation to separate functions. But this suggestion makes a lot of sense - collect all your data and then render it once without rendering pieces of your data as you go.

or even just go all-in with the iteration

```
runPlanets earthWeight =
forM_ [minBound .. maxBound] $ \planet -> do
let newWeight = surfaceWeight mass planet
putStrLn $ "Your mass on " <> show planet <> ...
where
mass =
let SurfaceGravity earthGravity = surfaceGravity EARTH
in Mass $ earthWeight / earthGravity
```

Another interesting suggestion.

I think the biggest trap I fell into while encoding the Java solution into Haskell was just that - Encoding a Java solution into Haskell. Instead, I should have solved it in the way Haskell enables you to.

asthetaperlight had some ideas on the use of newtypes:

For throwaway code like this, sure. But it would also be fine to write it as a shell script, if for some reason you really felt like it. Dimensional analysis is the static typing of physics. Not the fancy stuff that makes you want to use Haskell instead of Java - the “has literally any types at all” that makes you want to use C instead of B. Better to build good habits before you need them.

That said, SurfaceWeight doesn’t make much sense as written. Either go all in and tag it with a phantom Planet …

`SurfaceWeight`

didn’t really make much sense on its own. I love the idea about saying “this is the weight on this planet” and tagging the weight with a phantom Planet.

The warning around using the above technique is funny and cautions against using unnecessary complexity:

Then seriously rethink whatever aspect of your design made that seem necessary …

😂

or make it what it is: newtype Weight = Weight Double.

`SurfaceWeight`

seems too specific and `Weight`

seems like a more natural wrapper type.

friedbrice has some interesting insights:

Nice post, I hope you’re enjoying Haskell.

One thing that I find interesting, you bring up a decisive difference between object oriented programming and functional programming: how object oriented programming packages data and behavior together, and how functional programming separates data and behavior. it may seem like a bummer at first that you have to write each enum value twice, once when the data is defined, and once when the behavior is defined, but there’s a very good reason that functional programming encourages this separation.

I think we anthropomorphize the computer too much, and so I don’t like calling it behavior. I like calling it interpretation, specifically interpretation of the data. One common theme of object oriented programming is that the downstream user is not allowed to interpret the data. The data is hidden from them, and the interpretation is defined solely by the upstream user. sometimes, this is exactly what you want. Haskell has many ways to hide data, not least of all are simple things like partial application and closures, hiding through scope instead of access modifiers.

The problem is that object oriented programming insists that you always hide your data like this. most of the time, you don’t want to hide your data. Your behavior, your planet stats, is one interpretation of the data. The power of functional programming is that it need not be the only interpretation.

This idea of “data” having multiple “interpretations” is pretty cool. It’s something I had not thought of explicitly before. As previously mentioned by brandonchinn178, we could define a function each to get the `mass`

and `radius`

from a `Planet`

as opposed to a `PlanetStat`

. This is yet another interpretation of the `Planet`

“data”.

```
module Recommendations.Brandonchinn178.Planets_1(runPlanets) where
import Data.Foldable (traverse_)
-- Haskell implementation of the Java Enum: Planets example
-- https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
import Data.Foldable (traverse_)
data Planet = MERCURY
| VENUS
| EARTH
| MARS
| JUPITER
| SATURN
| URANUS
| NEPTUNE deriving (Enum, Bounded, Show)
newtype Mass = Mass Double
newtype Radius = Radius Double
gConstant :: Double
gConstant = 6.67300E-11
radius :: Planet -> Radius
radius MERCURY = Radius 2.4397e6
radius VENUS = Radius 6.0518e6
radius EARTH = Radius 6.37814e6
radius MARS = Radius 3.3972e6
radius JUPITER = Radius 7.1492e7
radius SATURN = Radius 6.0268e7
radius URANUS = Radius 2.5559e7
radius NEPTUNE = Radius 2.4746e7
mass :: Planet -> Mass
mass MERCURY = Mass 3.303e+23
mass VENUS = Mass 4.869e+24
mass EARTH = Mass 5.976e+24
mass MARS = Mass 6.421e+23
mass JUPITER = Mass 1.9e+27
mass SATURN = Mass 5.688e+26
mass URANUS = Mass 8.686e+25
mass NEPTUNE = Mass 1.024e+26
surfaceGravity :: Planet -> Double
surfaceGravity planet =
let (Mass m) = mass planet
(Radius r) = radius planet
in gConstant * m / (r * m)
surfaceWeight :: Mass -> Planet -> Double
surfaceWeight (Mass otherMass) planet =
let sg = surfaceGravity planet
in otherMass * sg
runPlanets :: Double -> IO ()
runPlanets sampleWeight =
let earthSurfaceGravity = surfaceGravity EARTH
massOnEarth :: Mass
massOnEarth = Mass $ sampleWeight / earthSurfaceGravity
planetToWeight = map (\p -> (p, surfaceWeight massOnEarth p)) [minBound .. maxBound]
render (p, weight) = "Your weight on " <> show p <> " is " <> (show weight)
in mapM_ (putStrLn . render) planetToWeight
```

```
module Recommendations.Brandonchinn178.Planets_2(runPlanets) where
import Data.Foldable (forM_, traverse_)
-- Haskell implementation of the Java Enum: Planets example
-- https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
import Data.Foldable (traverse_)
data Planet = MERCURY
| VENUS
| EARTH
| MARS
| JUPITER
| SATURN
| URANUS
| NEPTUNE deriving (Enum, Bounded, Show)
newtype Mass = Mass Double
newtype Radius = Radius Double
gConstant :: Double
gConstant = 6.67300E-11
radius :: Planet -> Radius
radius MERCURY = Radius 2.4397e6
radius VENUS = Radius 6.0518e6
radius EARTH = Radius 6.37814e6
radius MARS = Radius 3.3972e6
radius JUPITER = Radius 7.1492e7
radius SATURN = Radius 6.0268e7
radius URANUS = Radius 2.5559e7
radius NEPTUNE = Radius 2.4746e7
mass :: Planet -> Mass
mass MERCURY = Mass 3.303e+23
mass VENUS = Mass 4.869e+24
mass EARTH = Mass 5.976e+24
mass MARS = Mass 6.421e+23
mass JUPITER = Mass 1.9e+27
mass SATURN = Mass 5.688e+26
mass URANUS = Mass 8.686e+25
mass NEPTUNE = Mass 1.024e+26
surfaceGravity :: Planet -> Double
surfaceGravity planet =
let (Mass m) = mass planet
(Radius r) = radius planet
in gConstant * m / (r * m)
surfaceWeight :: Mass -> Planet -> Double
surfaceWeight (Mass otherMass) planet =
let sg = surfaceGravity planet
in otherMass * sg
runPlanets :: Double -> IO ()
runPlanets earthWeight =
forM_ [minBound .. maxBound] $ \planet -> do
let newWeight = surfaceWeight mass planet
putStrLn $ "Your weight on " <> show planet <> " is " <> (show newWeight)
where
mass =
let earthGravity = surfaceGravity EARTH
in Mass $ earthWeight / earthGravity
```

```
module Recommendations.Asthetaperlight.Planets(runPlanets) where
-- Haskell implementation of the Java Enum: Planets example
-- https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
import Data.Foldable (traverse_)
data Planet = MERCURY
| VENUS
| EARTH
| MARS
| JUPITER
| SATURN
| URANUS
| NEPTUNE deriving (Enum, Bounded, Show)
newtype Mass = Mass Double
newtype Radius = Radius Double
data PlanetStat =
PlanetStat {
mass :: Mass
, radius :: Radius
}
newtype SurfaceGravity = SurfaceGravity Double
newtype Weight = Weight Double
gConstant :: Double
gConstant = 6.67300E-11
planetStat :: Planet -> PlanetStat
planetStat MERCURY = PlanetStat (Mass 3.303e+23) (Radius 2.4397e6 )
planetStat VENUS = PlanetStat (Mass 4.869e+24) (Radius 6.0518e6 )
planetStat EARTH = PlanetStat (Mass 5.976e+24) (Radius 6.37814e6)
planetStat MARS = PlanetStat (Mass 6.421e+23) (Radius 3.3972e6 )
planetStat JUPITER = PlanetStat (Mass 1.9e+27 ) (Radius 7.1492e7 )
planetStat SATURN = PlanetStat (Mass 5.688e+26) (Radius 6.0268e7 )
planetStat URANUS = PlanetStat (Mass 8.686e+25) (Radius 2.5559e7 )
planetStat NEPTUNE = PlanetStat (Mass 1.024e+26) (Radius 2.4746e7 )
surfaceGravity :: Planet -> SurfaceGravity
surfaceGravity planet =
let (PlanetStat (Mass mass) (Radius radius)) = planetStat planet
in SurfaceGravity $ gConstant * mass / (radius * radius)
surfaceWeight :: Mass -> Planet -> Weight
surfaceWeight (Mass otherMass) planet =
let (SurfaceGravity sg)= surfaceGravity planet
in Weight $ otherMass * sg
runPlanets :: Double -> IO ()
runPlanets earthWeight =
let (SurfaceGravity earthSurfaceGravity) = surfaceGravity EARTH
massOnEarth :: Mass
massOnEarth = Mass $ earthWeight / earthSurfaceGravity
planetValues :: [Planet]
planetValues = [(minBound :: Planet) .. (maxBound :: Planet)]
printSurfaceWeight :: Planet -> Weight -> String
printSurfaceWeight planet (Weight sw) = "Your weight on " <> (show planet) <> " is " <> (show sw)
planetStatsStrings :: [String]
planetStatsStrings = (\p -> printSurfaceWeight p (surfaceWeight massOnEarth p)) <$> planetValues
in
traverse_ putStrLn planetStatsStrings
```

And here’s the final implementation I decided to use given the above recommendations:

```
module Final.Planets(runPlanets) where
import Data.Foldable (traverse_)
-- Haskell implementation of the Java Enum: Planets example
-- https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
import Data.Foldable (traverse_)
data Planet = MERCURY
| VENUS
| EARTH
| MARS
| JUPITER
| SATURN
| URANUS
| NEPTUNE deriving (Enum, Bounded, Show)
newtype Mass = Mass Double
newtype Radius = Radius Double
gConstant :: Double
gConstant = 6.67300E-11
radius :: Planet -> Radius
radius MERCURY = Radius 2.4397e6
radius VENUS = Radius 6.0518e6
radius EARTH = Radius 6.37814e6
radius MARS = Radius 3.3972e6
radius JUPITER = Radius 7.1492e7
radius SATURN = Radius 6.0268e7
radius URANUS = Radius 2.5559e7
radius NEPTUNE = Radius 2.4746e7
mass :: Planet -> Mass
mass MERCURY = Mass 3.303e+23
mass VENUS = Mass 4.869e+24
mass EARTH = Mass 5.976e+24
mass MARS = Mass 6.421e+23
mass JUPITER = Mass 1.9e+27
mass SATURN = Mass 5.688e+26
mass URANUS = Mass 8.686e+25
mass NEPTUNE = Mass 1.024e+26
newtype Gravity = Gravity Double deriving Show
newtype Weight = Weight Double deriving Show
surfaceGravity :: Planet -> Gravity
surfaceGravity planet =
let (Mass mass') = mass planet
(Radius radius') = radius planet
in Gravity $ gConstant * mass' / (radius' * radius')
surfaceWeight :: Mass -> Planet -> Weight
surfaceWeight (Mass otherMass) planet =
let (Gravity sg)= surfaceGravity planet
in Weight $ otherMass * sg
runPlanets :: Double -> IO ()
runPlanets sampleWeight =
let (Gravity earthSurfaceGravity) = surfaceGravity EARTH
massOnEarth :: Mass
massOnEarth = Mass $ sampleWeight / earthSurfaceGravity
planetToWeight :: [(Planet, Weight)]
planetToWeight = map (\p -> (p, surfaceWeight massOnEarth p)) [minBound .. maxBound]
render :: (Planet, Weight) -> String
render (p, weight) = "Your weight on " <> show p <> " is " <> (show weight)
in mapM_ (putStrLn . render) planetToWeight
```

```
public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7);
private final double mass; // in kilograms
private final double radius; // in meters
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
private double mass() { return mass; }
private double radius() { return radius; }
// universal gravitational constant (m3 kg-1 s-2)
public static final double G = 6.67300E-11;
double surfaceGravity() {
return G * mass / (radius * radius);
}
double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Usage: java Planet <earth_weight>");
System.exit(-1);
}
double earthWeight = Double.parseDouble(args[0]);
double mass = earthWeight/EARTH.surfaceGravity();
for (Planet p : Planet.values())
System.out.printf("Your weight on %s is %f%n",
p, p.surfaceWeight(mass));
}
}
```

This seemed fairly easy. I started off by modelling a Planet and associated data:

```
data Planet = MERCURY
| VENUS
| EARTH
| MARS
| JUPITER
| SATURN
| URANUS
| NEPTUNE deriving (Enum, Bounded, Show)
newtype Mass = Mass Double
newtype Radius = Radius Double
data PlanetStat =
PlanetStat {
mass :: Mass
, radius :: Radius
}
newtype SurfaceGravity = SurfaceGravity Double
newtype SurfaceWeight = SurfaceWeight Double
gConstant :: Double
gConstant = 6.67300E-11
```

One difference between Haskell and OOP languages is that Haskell separates out data from behaviour while OOP languages combine data (or state) and behaviour into one construct - a class.

In Java, `surfaceGravity`

and `surfaceWeight`

are bound to a particular Planet instance. In Haskell, as mentioned above, we don’t have behaviour and state stored together. How do we go about implementing these functions in Haskell?

Instead of having state and behaviour combined, we can **use** the state to derive any behaviour we need:

```
surfaceGravity :: Planet -> SurfaceGravity
surfaceGravity planet =
let (PlanetStat (Mass mass) (Radius radius)) = planetStat planet
in SurfaceGravity $ gConstant * mass / (radius * radius)
surfaceWeight :: Mass -> Planet -> SurfaceWeight
surfaceWeight (Mass otherMass) planet =
let (SurfaceGravity sg)= surfaceGravity planet
in SurfaceWeight $ otherMass * sg
```

Notice how we pass in the `Planet`

instance we need to each function above. We don’t have a `this`

reference as in most OOP languages. Here’s the Java implementation of the above functions with an explicit `this`

reference added:

```
double surfaceGravity() {
return G * this.mass / (this.radius * this.radius);
}
double surfaceWeight(double otherMass) {
return otherMass * this.surfaceGravity();
}
```

That solves one problem, but there’s another. It has to do with retrieving all the values of an enumeration. In the Java example we use:

`Planet.values()`

How do we get all the values of an enumeration in Haskell?

You may have noticed the `deriving (Enum, Bounded ...)`

syntax against the `Planet`

data type. Using the Enum and Bounded type classes we can retrieve all the values of the `Planet`

sum type:

```
planetValues :: [Planet]
planetValues = [(minBound :: Planet) .. (maxBound :: Planet)]
```

The above code, grabs the first (`minBound`

) and last (`maxBound`

) values of the `Planet`

sum type and the range syntax (`..`

) makes it possible to enumerate all the values in between. Pretty nifty! The range syntax is made possible by having an `Enum`

instance for a data type. See the `enumFrom`

, `enumFromThen`

, `enumFromThenTo`

and `enumFromTo`

functions on the `Enum`

type class for more information.

It’s starting to look like we’ve got this solved pretty easily. Unfortunately we have another small problem. The `planetValues`

function only gives us the `Planet`

sum type - essentially the names of the planets. We also need to retrieve the mass and radius for each planet as per Java:

```
public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7);
...
```

How do we go about doing this?

We could create a Map with `Planet`

as the key and `PlanetStat`

as the value. So far so good. But when we go to look up a value we have to use the lookup function:

`lookup :: Ord k => k -> Map k a -> Maybe a`

The return type of the `lookup`

function is a Maybe. This means we have to deal with the possibility of not finding a particular `Planet`

(the `Nothing`

case):

```
-- planetMap :: Map Planet PlanetStat
case (lookup somePlanet planetMap) of
Just planet -> -- cool planet-related stuff
Nothing -> -- this should never happen!
```

We know this is impossible because we have a sum type for `Planet`

, but because we are using a `Map`

we need to deal with it.

Another way to encode this mapping is like this:

```
planetStat :: Planet -> PlanetStat
planetStat MERCURY = PlanetStat (Mass 3.303e+23) (Radius 2.4397e6 )
planetStat VENUS = PlanetStat (Mass 4.869e+24) (Radius 6.0518e6 )
planetStat EARTH = PlanetStat (Mass 5.976e+24) (Radius 6.37814e6)
planetStat MARS = PlanetStat (Mass 6.421e+23) (Radius 3.3972e6 )
planetStat JUPITER = PlanetStat (Mass 1.9e+27 ) (Radius 7.1492e7 )
planetStat SATURN = PlanetStat (Mass 5.688e+26) (Radius 6.0268e7 )
planetStat URANUS = PlanetStat (Mass 8.686e+25) (Radius 2.5559e7 )
planetStat NEPTUNE = PlanetStat (Mass 1.024e+26) (Radius 2.4746e7 )
```

This way we don’t have to deal with any optionality; this is a total function.

It’s interesting that Java gives us this mapping for “free” because it combines state and behaviour. In Haskell you need to bring state and behaviour together as required. A big thanks to my friend Adam for pointing this out. In hindsight it seems obvious.

And that’s about it for surprises. Here’s the full solution:

```
import Data.Foldable (traverse_)
data Planet = MERCURY
| VENUS
| EARTH
| MARS
| JUPITER
| SATURN
| URANUS
| NEPTUNE deriving (Enum, Bounded, Show)
newtype Mass = Mass Double
newtype Radius = Radius Double
data PlanetStat =
PlanetStat {
mass :: Mass
, radius :: Radius
}
newtype SurfaceGravity = SurfaceGravity Double
newtype SurfaceWeight = SurfaceWeight Double
gConstant :: Double
gConstant = 6.67300E-11
planetStat :: Planet -> PlanetStat
planetStat MERCURY = PlanetStat (Mass 3.303e+23) (Radius 2.4397e6 )
planetStat VENUS = PlanetStat (Mass 4.869e+24) (Radius 6.0518e6 )
planetStat EARTH = PlanetStat (Mass 5.976e+24) (Radius 6.37814e6)
planetStat MARS = PlanetStat (Mass 6.421e+23) (Radius 3.3972e6 )
planetStat JUPITER = PlanetStat (Mass 1.9e+27 ) (Radius 7.1492e7 )
planetStat SATURN = PlanetStat (Mass 5.688e+26) (Radius 6.0268e7 )
planetStat URANUS = PlanetStat (Mass 8.686e+25) (Radius 2.5559e7 )
planetStat NEPTUNE = PlanetStat (Mass 1.024e+26) (Radius 2.4746e7 )
surfaceGravity :: Planet -> SurfaceGravity
surfaceGravity planet =
let (PlanetStat (Mass mass) (Radius radius)) = planetStat planet
in SurfaceGravity $ gConstant * mass / (radius * radius)
surfaceWeight :: Mass -> Planet -> SurfaceWeight
surfaceWeight (Mass otherMass) planet =
let (SurfaceGravity sg)= surfaceGravity planet
in SurfaceWeight $ otherMass * sg
runPlanets :: Double -> IO ()
runPlanets earthWeight =
let (SurfaceGravity earthSurfaceGravity) = surfaceGravity EARTH
massOnEarth :: Mass
massOnEarth = Mass $ earthWeight / earthSurfaceGravity
planetValues :: [Planet]
planetValues = [(minBound :: Planet) .. (maxBound :: Planet)]
printSurfaceWeight :: Planet -> SurfaceWeight -> String
printSurfaceWeight planet (SurfaceWeight sw) = "Your weight on " <> (show planet) <> " is " <> (show sw)
planetStatsStrings :: [String]
planetStatsStrings = (\p -> printSurfaceWeight p (surfaceWeight massOnEarth p)) <$> planetValues
in
traverse_ putStrLn planetStatsStrings
```

The source code for the example can be found on Github.

If there are any easier/better ways to encode this example in Haskell, please free to drop in comment.

]]>Make the change easy, then make the easy change

I heard it first on the Elm Radio podcast. This was some very useful advice on how to introduce changes to a code base. First make it easy to introduce the change by refactoring your code, adding in tests etc. Then swoop in an add your change with minimal fuss. This is a nice reusable technique.

Kent Beck originally said this back in 2012. I remember mentioning this pattern to a few colleagues at work and sure enough even months later they still keep referring to it.

If something is memorable, you are more likely to use it solve a given problem.

This got me thinking:

Is memorable advice more useful than unmemorable advice?

It seems obvious in hindsight. What good is advice if no one remembers it?

Another phrase I heard of recently was

Teach me how to message

a technique used by Richard Feldman to identify functions of the following type in Elm:

`(CustomType -> msg)`

Based on how you implement this function, you “teach” it how to create the appropriate message. Here’s an example from Richard’s presentation:

```
Article.view :
(Article a -> msg) //teach this how to message
-> Article a
-> Html msg
```

Now everytime I see a function of the above shape I always think that it needs me to teach it how to message. Somehow that makes it easier to implement this function. I know what it “needs”.

There is something calming about seeing a problem in the code and knowing how to go about solving it. These catchy phrases become part of your swissarmy knife used to carve out solutions.

The next time you has stumbled on a great technique on how to solve a problem try and package it in memorable way.

]]>```
versionRange failure: FAIL
✗ versionRange failure failed at test/DBPropSpec.hs:41:54
after 1 test and 2 shrinks.
┏━━ test/DBPropSpec.hs ━━━
25 ┃ hprop_versionRange_failure :: H.Property
26 ┃ hprop_versionRange_failure =
27 ┃ H.property $ do
28 ┃ minR <- H.forAll $ Gen.int (Range.linear 0 99)
┃ │ 0
29 ┃ maxR <- H.forAll $ Gen.int (Range.linear (minR + 1) 200)
┃ │ 1
30 ┃ let upperG :: H.Gen Int = Gen.int (Range.linear maxR (maxR + 100))
31 ┃ lowerG :: H.Gen Int = Gen.int (Range.linear (minR - 100) minR)
32 ┃ minMax = (D.VersionRange minR maxR)
33 ┃ versionE <- H.forAll $ Gen.either lowerG upperG
┃ │ Left 0
34 ┃ either (assertVersionRangeFailure minMax) (assertVersionRangeFailure minMax) versionE
35 ┃ where
36 ┃ assertVersionRangeFailure :: D.VersionRange -> Int -> H.PropertyT IO ()
37 ┃ assertVersionRangeFailure maxMin version =
38 ┃ let range = D.versionRange maxMin (D.mkNoteVersion version)
39 ┃ in case range of
40 ┃ (D.InvalidNoteVersionRange v r) -> (r H.=== maxMin) >> (v H.=== version)
41 ┃ (D.ValidNoteVersionRange _) -> H.failure
┃ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This failure can be reproduced by running:
> recheck (Size 99) (Seed 15737640735508047734 16943050916655939693) versionRange failure
Use '--hedgehog-replay "Size 99 Seed 15737640735508047734 16943050916655939693"' to reproduce.
```

While the output mentions that we can rerun the failed property with:

`Use '--hedgehog-replay "Size 99 Seed 15737640735508047734 16943050916655939693"' to reproduce.`

We can’t use this information directly if we are running the tests through Tasty and Stack. I had previously blogged about How to run specific tests through Stack with Tasty in Haskell. From that article we know about the `--ta`

parameter which enables us to pass parameters to the underlying testing framework:

`--ta,--test-arguments TEST_ARGS Arguments passed in to the test suite program`

Using that information we can now rerun the Hedgehog property like so:

`stack test --ta '--hedgehog-replay "Size 100 Seed 15737640735508047734 16943050916655939693"'`

Unfortunately this will run all the tests including the ones that are not affected by the failing seed. From the post mentioned previously we know how to use the `-p`

parameter to run specific tests:

`-p,--pattern ARG Select only tests that match pattern`

Using that information we can now rerun just the affect Hedgehog test with the provided seed:

`stack test --ta '--hedgehog-replay "Size 100 Seed 15737640735508047734 16943050916655939693" -p "your_spec_name"'`

While this is quite cumbersome to use I hope this will help anyone else who was stumped by how to simply rerun a failed Hedgehog property through tasty and Stack.

]]>`Capslock`

button and it was - I could see the `Capslock`

light turning on and off. Surprisingly I could still move the mouse pointer around the screen but I couldn’t click on any of the UIs and make them do anything.
As you can imagine this was quite frustrating and I was wondering if I should upgrade my Macosx from `Mojave`

to `Catalina`

. I had been dreading this upgrade because Apple usually ends up breaking something and then I have to waste my time tending to those issues.

I also seemed to be able to quite regularly make the system freeze by switching between windows in Sublime Text or moving to another window or typing in the terminal. Almost anything really, but nothing conclusive.

I had also had a look in `Activity Monitor`

after a freeze and didn’t find anything out of the ordinary using of a lot of CPU or RAM. I also had plenty of disc space.

One of the services I did notice in `Activity Monitor`

was `com.apple.hiservices-xpcservice`

- which was `not responding`

. I killed it manually but it didn’t make things better (or worse). It was not always `not responding`

after a freeze.

Some people had different results though.

The freezes were getting progressively more frequent. Suddenly one day I couldn’t launch Alfred with my usual key combination. I could see that `Alfred`

was working and I could manually launch it by clicking on its icon in the system tray but my key combinations no longer worked :(

I had recently purchased a Durgod K320 Taurus and I thought that maybe it was failing - after all, most of my freezes had happened when using the keyboard to do one thing or another.

After the next freeze, I noticed that my character set had changed and now when I typed I was seeing some weird characters. This seemed to confirm my suspicions of the `Durgod`

and I unplugged and replugged it into my USB hub. The character set was back to normal. So I figured that the keyboard was faulty. I did some Google searches but didn’t find too many people complaining about this issue with the `Durgod`

.

After a while I came across a sure-fire way to cause my laptop to freeze - Switching between windows of by various Sublime Text windows.

So maybe the problem was with Sublime Text? Given that I did most of my development in Sublime Text it might be the culprit. I found a newer version of Sublime Text than I was using and installed it. I even considered installing an alpha version of `Sublime Text 4`

to see if that was any better.

Unfortunately that did not solve the problem.

At this point I launched into a full hardware diagnostic:

Restart your Mac and then hold the

`D`

key when it starts up

It came back clean except for the battery which was not at a 100%. This was fine given its age.

The diagnostic recommended unplugging all peripherals before running it. So I unplugged my keyboard, mouse, 4K monitor and headphones before proceeding.

The interesting thing was that, when I used the laptop by itself, I couldn’t cause the freeze by switching between `Sublime Text`

windows. Wow! At least my laptop was not dying and I probably didn’t have to reinstall or upgrade MacOS versions. Yay?

At this point it looked like the output to the 4K monitor maybe causing the issue. I did some investigation and some people had issues around using 4K monitors with the Mac.

One of the remedies recommended with hardware issues was to reset the `NVRAM`

and `PRAM`

:

NVRAM (nonvolatile random-access memory) is a small amount of memory that your Mac uses to store certain settings and access them quickly. PRAM (Parameter RAM) stores similar information, and the steps for resetting NVRAM and PRAM are the same.

I noticed that `display resolution`

was among the settings that were stored in NVRAM:

Settings that can be stored in NVRAM include sound volume, display resolution, startup disk selection, time zone and recent kernel panic information. The settings stored in NVRAM depend on your Mac and the devices that you’re using with your Mac

I followed the recommended instructions to reset the NVRam:

- Shutdown mac
- Press the power button
- Press and hold
`ALT`

+`CMD`

+`P`

+`R`

until you hear the second chime sound

And voila! All my issues were fixed!! Hooray!!

So there you have it. If you have similar issues NVRAM might be the culprit! Also try just using the laptop without any peripherals plugged in to see if any of them are causing the issue.

- whats-causing-my-macbook-to-freeze-and-reset-keyboard-settings-when-i-bring-it
- https://support.apple.com/en-au/HT202731
- https://www.ifixit.com/Answers/View/141693/Why+is+my+keyboard-trackpad+not+working
- https://discussions.apple.com/thread/251312151
- https://support.apple.com/en-au/HT204063
- https://apple.stackexchange.com/questions/342706/com-apple-hiservices-xpcservice-results-in-frequent-hangs-and-freezes-in-my-mac
- https://discussions.apple.com/thread/7370642
- https://discussions.apple.com/thread/6777878

A functor is a mapping between categories

and `Functor`

and `Contravariant`

to specify the typeclass encodings of functors.

Let’s begin!

Contravariant functors are odd aren’t they? Covariant functors (which are modelled by the `Functor`

typeclass) are quite straightforward but **contra**variant functors as their name implies seem to be the complete opposite.

Before we get into what a contravariant functor is, it’s useful to look at the `Functor`

typeclass which we know and love.

A `Functor`

is defined as:

```
class Functor f where
fmap :: (a -> b) -> f a -> f b
```

We often understand a `Functor`

to be a “container” or a “producer” of some type, where the function supplied to `fmap`

is applied to the elements that are “contained” or “produced” in some type constructor^{1} `f`

.

A simple example would be the list (`[]`

) type, that can represent zero or more values. Given a `[a]`

we can turn it into a `[b]`

when given a function `a -> b`

.

```
data [] a = [] | a : [a] -- an approximation of the [] data type
instance Functor [] where
fmap _ [] = []
fmap f (x:xs) = f x : fmap f xs
```

In the example below we convert a `[Int]`

into a `[String]`

given a function `Int -> String`

:

```
import Data.Semigroup ((<>))
myInts :: [Int]
myInts = [1 .. 5]
emptyInts :: [Int]
emptyInts = []
intToString :: Int -> String
intToString n = (show n) <> "!"
myStrings :: [String]
myStrings = fmap intToString myInts -- ["1!","2!","3!","4!","5!"]
myEmptyString :: []
myEmptyString = fmap intToString emptyInts -- []
```

Another example would the `Maybe`

data type, that represents a value that may or may not exist.

```
data Maybe a = Nothing | Just a
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just x) = Just (f x)
```

In the example below we convert a `Maybe Int`

into a `Maybe String`

given a function `Int -> String`

:

```
import Data.Semigroup ((<>))
maybeInt :: Maybe Int
maybeInt = Just 10
notInt :: Maybe Int
notInt = Nothing
intToString :: Int -> String
intToString n = (show n) <> "!"
maybeString :: Maybe String
maybeString = fmap intToString maybeInt -- Just "10!"
notString :: Maybe String
notString = fmap intToString notInt -- Nothing
```

The `Functor`

typeclass has laws, that ensure `Functor`

instances behave in a predictable way.

`fmap id == id`

Essentially if you do nothing to the value of a `Functor`

, you get the same `Functor`

you started with.

`fmap (f . g) == fmap f . fmap g`

If you convert the result of a Functor by `fmap`

ing with a function `g`

and then `fmap`

ing that result with a subsequent function `f`

, it’s the same as composing functions `g`

and `f`

(`f . g`

) and then `fmap`

ing once.

Now let’s look at something a little different. Let’s create a data type to wrap a predicate of some sort. A predicate is something that will evaluate to a `Bool`

:

`newtype Predicate a = Predicate { getPredicate :: a -> Bool }`

An example of a Predicate is `greaterThanTen`

:

```
greaterThanTen :: Predicate Int
greaterThanTen = Predicate (\n -> n > 10)
```

that tests whether a number is greater than ten.

We can run with it `getPredicate`

and an `Int`

:

```
getPredicate greateThanTen 5 -- False
getPredicate greateThanTen 11 -- True
```

It could be useful to define a `Functor`

instance for Predicate - say if we have a `Predicate Int`

and we want to convert it into a `Predicate String`

when we have a `Int -> String`

function. Let’s try and implement that:

```
instance Functor Predicate where
-- fmap (a -> b) -> Predicate a -> Predicate b
fmap f (Predicate p) = Predicate (\b -> undefined)
fmap f (Predicate (a -> Bool)) = Predicate (\b -> undefined) -- expanding p
fmap (a -> b) (Predicate (a -> Bool)) = Predicate (\b -> undefined) -- expanding f
```

Now we’ve run into a small problem:

How do we compose (a -> Bool) and (a -> b) to give us a (b -> Bool) ?

We are given a `b`

but we don’t have access to any functions that actually use a `b`

.

The problem is that we can’t. It’s because of something called “polarity” of the type variable `a`

. No `Functor`

instance for you `Predicate`

.

Polarity is a way of representing variance using the position of type variables. Let’s take a simple function `a -> b`

as an example.

If a type variable is in **input** position like `a`

it is given a **negative** polarity. If it is in an **output** position like `b`

then it is given a **positive** polarity.

These polarities map directly to variant types.

Polarity | Variance |
---|---|

Positive | Covariant |

Negative | Contravariant |

Both | Invariant |

What this means is that `Functor`

s (which are actually covariant functors) require a type constructor in a covariant position in order for you to define a `Functor`

instance for that type.

Let’s look at a type that we know has a `Functor`

instance like `Maybe`

:

We can see that the type variable `a`

occurs in a covariant (or output) position within the definition of the `Just`

constructor.

Now let’s look at the definition of `Predicate`

data type:

We can see that the type variable `a`

occurs in a contravariant (or input) position. This indicates that we can’t create a (covariant) `Functor`

instance for this data type.

But we want to map things! What do we do?

Welcome the `Contravariant`

typeclass to the stage! It’s defined as:

```
class Contravariant f where
contramap :: (a -> b) -> f b -> f a
```

Snazzy! `Contravariant`

also takes some kind of type constructor `f`

just like `Functor`

but it has this weirdly named `contramap`

function instead of `fmap`

.

```
fmap :: (a -> b) -> f a -> f b -- Functor
contramap :: (a -> b) -> f b -> f a -- Contravariant
^^^
```

If we read `fmap`

as:

If you have an

`a`

in some context and a function that takes that`a`

and converts it to a`b`

, I can give you a context with a`b`

in it.

we can then read `contramap`

as:

If you have a context that needs an

`a`

and a function that can convert`b`

s to`a`

s, I can give you a context that needs`b`

s.

But that probably doesn’t make much sense. So let’s try and look at this in terms of our non-`Functor`

: `Predicate`

. `Predicate`

has a **need** for an `a`

, which it then uses to tell if something about that `a`

is True or False.

Let’s try and write a `Contravariant`

instance for `Predicate`

given that we know that the type `a`

in `Predicate`

occurs in an input position.

```
instance Contravariant Predicate where
-- contramp (a -> b) -> f b -> f a
contramap (a -> b) -> Predicate b -> Predicate a -- substituting for `f` for Predicate
contramap aToB (Predicate bToBool) = Predicate (\a -> undefined)
```

Given that we have a function `a -> b`

and essentially a function of type `b -> Bool`

(wrapped inside a `Predicate b`

), we can if given an `a`

, convert it to a `b`

using `aToB`

and then give that `b`

to `bToBool`

to give us a `Bool`

.

Here’s a slightly long-form implementation of the `Contravariant`

instance for `Predicate`

:

```
instance Contravariant Predicate where
contramap :: (a -> b) -> Predicate b -> Predicate a
contramap aToB (Predicate bToBool) =
Predicate $ \a ->
let b = aToB a
bool = bToBool b
in bool
```

or more succinctly:

```
instance Contravariant Predicate where
contramap :: (a -> b) -> Predicate b -> Predicate a
contramap f (Predicate b) = Predicate $ b . f
```

We can see from the definition of `Predicate a`

that all we are doing is running the supplied function `f`

**before** the function within `Predicate b`

. The reason we do that is to adapt a new input type to match an existing input type to gain some functionality.

If we revisit the (covariant) `Functor`

instance for `Maybe`

:

```
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap aToB (Just a) = Just (aToB a)
```

we can see that the function `aToB`

is run **after** we have a value of `a`

. We do that to convert a result of some type to another type.

These are the essential differences between covariant and contravariant functors:

Typeclass | Function runs | Purpose |
---|---|---|

Functor | after | Convert results |

Contravariant | before | Adapt inputs |

Now that we know the essential difference between `Functor`

and `Contravariant`

, let’s look at how we can use `contramap`

with our `Predicate`

class.

Given that we already have a `Predicate`

that determines whether a number is greater than ten:

```
numGreaterThanTen :: Predicate Int
numGreaterThanTen = Predicate (\n -> n > 10)
```

say we want to write another `Predicate`

that verifies that the length of String is greater than ten characters.

```
strLengthGreaterThanTen :: Predicate String
strLengthGreaterThanTen = Predicate (\s -> (length s) > 10)
```

Sure, that’s pretty contrived but bear with me. Let’s also say we have a `Person`

data type and we want to know if a person’s name is over ten characters long - if so we consider that to be a long name.

```
data Person = Person { personName :: String, personAge :: Int }
personLongName :: Predicate Person
personLongName = Predicate (\p -> (length . personName $ p) > 10)
```

And we can run these `Predicate`

s as:

```
getPredicate numGreaterThanTen 5 -- False
getPredicate numGreaterThanTen 20 -- True
getPredicate strLengthGreaterThanTen "hello" -- False
getPredicate strLengthGreaterThanTen "hello world" -- True
getPredicate personLongName $ Person "John" 30 -- False
getPredicate personLongName $ Person "Bartholomew" 30 -- True
```

And this is fine, but there’s some duplication across each of the `Predicate`

s - namely the part where we compare a number to ten:

```
(\n -> n > 10) -- Int
(\s -> (length s) > 10) -- String
(\p -> (length . personName $ p) > 10) -- Person
```

It would be nice if we didn’t have to repeat ourselves.

If we look at the differences between `numGreaterThanTen`

, `strLengthGreaterThanTen`

and `personLongName`

we can see that the only difference is that one works on an `Int`

and the others work on `String`

and `Person`

respectively. `strLengthGreaterThanTen`

and `personLongName`

each convert their input types to an `Int`

and then do the same comparison:

```
Predicate (\(n :: Int) ->
let num = id n
in num > 10 -- (1)
) -- numGreaterThanTen
Predicate (\(s :: String) ->
let num = length s
in num > 10 -- (1)
) -- strLengthGreaterThanTen
Predicate (\(p :: Person) ->
let name = personName p
num = length name
in num > 10 -- (1)
) -- personLongName
```

The above expansion of the functions demonstrates that even though the `Predicate`

s themselves have different input types, at the end they are all converted to a number which is compared against the number ten. This is tagged with `(1)`

in the above example.

We can also see that the only changes between the `Predicate`

s is the conversion from one type to another **before** running our comparison function `(1)`

. This is our clue that we can use `contramap`

here to reuse some functionality.

```
numGreaterThanTen :: Predicate Int
numGreaterThanTen = Predicate (\n -> n > 10)
strLengthGreaterThanTen2 :: Predicate String
strLengthGreaterThanTen2 = contramap length numGreaterThanTen -- convert the String to an Int, then pass it to numGreaterThanTen
personLongName2 :: Predicate Person
personLongName2 = contramap (length . personName) numGreaterThanTen -- convert the Person to an Int, then pass it to numGreaterThanTen
```

We get the same results as before:

```
getPredicate strLengthGreaterThanTen2 "hello" -- False
getPredicate strLengthGreaterThanTen2 "hello world" -- True
getPredicate personLongName2 $ Person "John" 30 -- False
getPredicate personLongName2 $ Person "Bartholomew" 30 -- True
```

Now we have rewritten `strLengthGreaterThanTen`

and `personLongName`

in terms of `numGreaterThanTen`

by just running a function before it to convert the types. This is a simple example of a Contravariant Functor where we can reuse some existing functionality for a given type if we can convert from our other types to that type through some mapping function.

We can also go a little further and reuse even more:

```
personLongName3 :: Predicate Person
personLongName3 = contramap personName strLengthGreaterThanTen -- convert the Person to a String, then pass it to strLengthGreaterThanTen
```

Just like `Functor`

has laws, `Contravariant`

also has laws. This is awesome - because laws make our lives easier.

`contramap id == id`

Essentially if you do not change the value of a `Contravariant`

functor, you get the same `Contravariant`

functor you started with.

`contramap f . contramap g = contramap (g . f)`

If you convert the input to some `Contravariant`

functor by `contramap`

ing with function `g`

and then convert its input to some other type by `contramap`

ing again with a function `f`

, it’s the same as composing the functions `f`

and `g`

(`g . f`

) and then `contramap`

ing once. Notice the order of composition is switched as opposed to when we looked at the `Functor`

laws.

Let’s take `Predicate`

as an example and try out the identity law. The `Contravariant`

instance for `Predicate`

is defined as:

```
instance Contravariant Predicate where
contramap :: (a -> b) -> f b -> f a
contramap f (Predicate p) = Predicate (p . f)
```

Given that we have a `Predicate Int`

:

```
numGreaterThanTen :: Predicate Int
numGreaterThanTen = Predicate (\n -> n > 10)
```

Using `contramap id`

on the above:

```
-- identity law
contramap id numGreaterThanTen == numGreaterThanTen
-- lhs
Predicate (p . f) -- applying contramap
Predicate (p . id) -- expanding f
Predicate (p) -- applying f
Predicate (\n -> n > 10) -- expanding p
-- rhs
numGreaterThanTen
Predicate (\n -> n > 10) -- expanding numGreaterThanTen
-- equality
lhs == rhs
Predicate (\n -> n > 10) == Predicate (\n -> n > 10)
```

Once again using `Predicate`

as an example, let’s explore the compositional law of `Contravariant`

.

Given that we have the following `Predicate`

s:

```
numGreaterThanTen :: Predicate Int
numGreaterThanTen = Predicate (\n -> n > 10)
length :: [a] -> Int
personName :: Person -> String
```

Using `numGreaterThanTen`

, with `length`

and `personName`

:

```
-- composition law
contramap personName . contramap length $ numGreaterThanTen = contramap (length . personName) numGreaterThanTen
-- lhs
contramap personName . contramap length $ numGreaterThanTen
contramap personName . contramap length $ Predicate (\n -> n > 10) -- expanding numGreaterThanTen
contramap personName (Predicate $ \str ->
let num = length str
bool = num > 10
in bool
) -- applying length
Predicate $ \person ->
let str = personName person
num = length str
bool = num > 10
in bool
) -- applying personName
=> Predicate Person
-- rhs
contramap (length . personName) numGreaterThanTen
contramap (\person ->
let str = personName person
num = length str
in num
) numGreaterThanTen -- expanding length . personName
Predicate (\person ->
let str = personName person
num = length str
bool = num > 10 -- expanding numGreaterThanTen
in bool
)
=> Predicate Person
-- equality
lhs == rhs
Predicate (\person ->
let str = personName person
num = length str
bool = num > 10
in bool
) ==
Predicate (\person ->
let str = personName person
num = length str
bool = num > 10
in bool
)
```

There are some built-in combinators that go with `Contravariant`

.

Similar to the `contramap`

function the following functions can be used infix:

```
-- infixl 4
(>$<) :: Contravariant f => (a -> b) -> f b -> f a
-- contramap :: Contravariant f => (a -> b) -> f b -> f a
```

A simple example of it in use:

```
p5 :: Predicate Int
p5 = Predicate $ \n -> n == 5
pLength5 :: Predicate [a]
pLength5 = length >$< p5
getPredicate pLength5 "hello"
-- True
getPredicate pLength5 "hello world"
-- False
```

Same as `contramap`

but with the parameters switched:

```
-- infixl 4
(>$$<) :: Contravariant f => f b -> (a -> b) -> f a
-- contramap :: Contravariant f => (a -> b) -> f b -> f a
```

These combinators take in a constant input and completely ignore the input supplied when running the `Contravariant`

instance.

```
-- infixl 4
(>$) :: b -> f b -> f a
```

It has a default implementation of:

```
(>$) :: b -> f b -> f a
(>$) = contramap . const
```

Let’s see how that works:

```
-- const when given two values returns the first value ignoring the second
const :: a -> b -> a
const x _ = x
contramap :: Contravariant f => (a -> b) -> f b -> f a
(>$) :: b -> f b -> f a
(>$) = contramap . const
(>$) b = contramap (const b) -- simplifying with b
(>$) b = contramap (a -> b) -- applying `const b`
(>$) b fb = contramap (a -> b) fb -- simplifying with fb
(>$) b fb = fa -- simplifying `contramap (a -> b) fb`
```

A simple example of it in use:

```
p5 :: Predicate Int
p5 = Predicate $ \n -> n == 5
pLength5 :: Predicate [a]
pLength5 = contramap length p5
getPredicate pLength5 "hello"
-- True
getPredicate pLength5 "hello world"
-- False
pAlwaysFalse :: Predicate [a]
pAlwaysFalse = 10 >$ p5
getPredicate pAlwaysFalse "hello"
-- False (because 10 /= 5)
getPredicate pAlwaysFalse "hello world"
-- False
```

Same as above but with the parameters switched:

```
-- infixl 4
($<) :: Contravariant f => f b -> b -> f a
```

Let’s look at another example of `Contravariant`

. Imagine you have the following data type that encapsulates performing some side effect on some polymorphic type `a`

:

`newtype LogAction a = LogAction { unlog :: a -> IO () }`

For our purposes we can assume that we are going to use this to log some value either to the console or to a file or some other medium. This example has been adapted from the LogAction class of the CO-LOG logging library. Definitely check out the library for real-world uses of `Contravariant`

and friends.

As we can see the type variable `a`

occurs in input position so we should be able to define a `Contravariant`

instance for it:

```
instance Contravariant LogAction where
contramap :: (b -> a) -> LogAction a -> LogAction b
contramap bToA logActionA = LogAction $ \b -> unlog logActionA (bToA b)
```

There should be no surprises here; we run the supplied function `bToA`

on the input *before* passing it to the log action.

Here’s a slightly simplified implementation of the above:

```
instance Contravariant LogAction where
contramap f logActionA = LogAction $ unlog logActionA . f
```

So how can we use `LogAction`

? Let’s define a couple of implementations:

```
putStrLog :: LogAction String
putStrLog = LogAction putStr
putStrLnLog :: LogAction String
putStrLnLog = LogAction putStrLn
```

`putStrLog`

and `putStrLn`

are just wrappers around `putStr`

and `putStrLn`

from `base`

. Both log a String to the console, the difference being that `putStrLn`

sends a newline character to the console after each call.

Here’s how we’d use `putStrLnLog`

:

```
unlog putStrLnLog "Hello World"
-- Hello World
```

Remember that `LogAction`

*needs* an `a`

which in this case is a `String`

.

Now because we have the power of contravariance, we should be able to log out other types if we can convert them to a `String`

.

Here are some examples:

```
-- simple function around contramap for LogAction
putStringlyLnLog :: (a -> String) -> LogAction a
putStringlyLnLog f = contramap f putStrLnLog
-- Now we can log Ints
putStrLnInt :: LogAction Int
putStrLnInt = putStringlyLnLog show
data Person = Person { name :: String, age :: Int }
-- custom String representation of Person
showPerson :: Person -> String
showPerson (Person name age) = "Person(name:" <> name <> ", age: " <> (show age) <> ")"
-- Now we can log people
putStrLnPerson :: LogAction Person
putStrLnPerson = putStringlyLnLog showPerson
-- custom String representation of Person that only displays age
showPersonAge :: Person -> String
showPersonAge person = "age: " <> (show $ age person)
-- Additional Person LogAction which outputs only age
putStrLnPersonAge :: LogAction Person
putStrLnPersonAge = putStringlyLnLog showPersonAge
```

Here’s how we can run the above:

```
unlog putStrLnInt 42
-- 42
unlog putStrLnPerson $ Person "Neelix" 60
-- Person(name:Neelix, age: 60)
unlog putStrLnPersonAge $ Person "Tuvok" 240
-- age: 240
```

We can see that `LogAction`

for `Person`

, *needs* a `Person`

instance as input to perform the log action.

Something that might not be obvious is that we can also adapt an input type to itself. It’s not necessary to always convert from one type to another.

Here are some example functions which we can use with `contramap`

:

```
hello :: String -> String
hello = ("Hello" <>)
there :: String -> String
there = ("there" <>)
doctor :: String -> String
doctor = ("Doctor" <>)
space :: String -> String
space = (" " <>)
```

Here’s how we compose the above functions into a `LogAction`

:

```
putStrLnGreeting :: LogAction String
putStrLnGreeting = contramap space . contramap doctor . contramap space . contramap there . contramap space . contramap hello $ putStrLnLog
```

Whoa! That’s even hard to read. What does it do? Remember from the second law of `Contravariant`

that:

`contramap f . contramap g = contramap (g . f)`

Given that, we can rewrite our highly compositional `LogAction`

like so:

```
putStrLnGreeting :: LogAction String
putStrLnGreeting = contramap (hello . space . there . space . doctor . space) $ putStrLnLog
```

At least this is somewhat more readable - but the great thing is that knowing the laws helped us make our code more legible. But still - what does this do?

The trick is to remember that `Contravaraint`

composition works in **reverse** to normal composition:

`contramap f . contramap g = contramap (g . f) -- notice the (g . f) instead of (f. g)`

This is how `putStrLnGreeting`

is evaluated:

```
putStrLnGreeting :: LogAction String
putStrLnGreeting = contramap (hello . space . there . space . doctor . space) $ putStrLnLog
unlog putStrLnGreeting "Switzer" -- run the logger with "Switzer" as the input
-- the input is going to go through this sequence of functions:
-- (hello . space . there . space . doctor . space)
-- applying space
" " <> Switzer
-- applying doctor
"Doctor" <> " " <> Switzer
-- applying space
" " <> "Doctor" <> " " <> Switzer
-- applying there
"there" <> " " <> "Doctor" <> " " <> Switzer
-- applying space
" " <> "there" <> " " <> "Doctor" <> " " <> Switzer
-- applying hello
"Hello" <> " " <> "there" <> " " <> "Doctor" <> " " <> Switzer
-- final output:
-- Hello there Doctor Switzer
```

Let’s look at one more `LogAction`

which might be interesting; One where we ignore the input and return some constant output:

```
override :: a -> a -> a
override value = const value
```

A we mentioned previously, `const`

is defined as `a -> b -> a`

, where it accepts two inputs but returns the value of the first input (ignoring the second input).

Here’s how we use it with `LogAction`

:

```
qPutStrLn ::LogAction String
qPutStrLn = contramap (override "This is Q!!") putStrLnLog
-- run it
unlog qPutStrLn "Picard J L"
-- This is Q!!
```

Now if our memory serves, we should be able to do the same with `>$`

:

```
qPutStrLnOp :: LogAction String
qPutStrLnOp = "This is Q!!" >$ putStrLnLog
-- run it
unlog qPutStrLnOp "Sisko B L"
-- This is Q!!
```

Now let’s look at two somewhat related concepts: equality and ordering

Let’s imagine that we have a datatype called `Equivalence`

that wraps an equality expression:

`newtype Equivalence a = Equivalence { getEquivalence :: a -> a -> Bool }`

Given two values of type `a`

the `getEquivalence`

function will return a `Bool`

indicating if they are equal or not.

Now we can see that both `a`

type variables are in input position. Let’s define a `Contravariant`

instance for it:

```
instance Contravariant Equivalence where
contramap :: (a -> b) -> Equivalence b -> Equivalence a
contramap aToB (Equivalence eqB1B2) = Equivalence $ \a1 a2 ->
let b1 = aToB a1
b2 = aToB a2
in eqB1B2 b1 b2
```

Something important to note is that the function we supply to `contramap`

(`a -> b`

) is run on twice - once on each of the input parameters (`b`

).

Given an `Equivalence`

for `Int`

:

```
intEq :: Equivalence Int
intEq = Equivalence (==)
```

We can run it as:

```
getEquivalence intEq 1 2
-- False
getEquivalence intEq 1 1
-- True
```

We can calculate the equivalence of other types using `contramap`

:

```
strLengthEq :: Equivalence String
strLengthEq = contramap length intEq
data Person = Person { name :: String, age :: Int }
personAgeEq :: Equivalence Person -- equality by age
personAgeEq = contramap age intEq
personNameLengthEq :: Equivalence Person -- equality by length of name
personNameLengthEq = contramap name strLengthEq
```

Here’s how we can run the above:

```
-- t1 = Person "Tuvok1" 240
-- t2 = Person "Tuvok2" 340
-- t3 = Person "Neelix" 60
-- t4 = Person "Janeway" 40
getEquivalence personAgeEq t1 t2
-- False
getEquivalence personAgeEq t1 t1
-- True
getEquivalence personAgeEq t2 t2
-- True
getEquivalence personAgeEq t2 t3
-- False
getEquivalence personNameLengthEq t1 t2
-- True
getEquivalence personNameLengthEq t3 t4
-- False
getEquivalence personNameLengthEq t1 t4
-- False
```

Let’s imagine that we have a datatype called `Comparison`

that wraps a comparison expression:

`newtype Comparison a = Comparison { getComparison :: a -> a -> Ordering }`

Given two values of type `a`

the `getComparison`

function will return an Ordering (`LT`

, `GT`

or `EQ`

) with respect to each other.

Now we can see that both `a`

type variables are in input position as before. Let’s define a `Contravariant`

instance for it:

```
instance Contravariant Comparison where
contramap :: (a -> b) -> Comparison b -> Comparison a
contramap aToB (Comparison cmpB1B2) = Comparison $ \a1 a2 ->
let b1 = aToB a1
b2 = aToB a2
in cmpB1B2 b1 b2
```

We can see that the wrappers for `Equivalence`

and `Comparison`

are almost the same, as are their `Contravariant`

instances.

Given a `Comparison`

for Int as:

```
intCmp :: Comparison Int
intCmp = Comparison compare
```

We can run it as:

```
getComparison intCmp 1 1
-- EQ
getComparison intCmp 1 2
-- LT
getComparison intCmp 2 1
-- GT
```

We can now calculate the comparison of other types using `contramap`

:

```
strCmp :: Comparison String
strCmp = contramap length intCmp
personAgeCmp :: Comparison Person
personAgeCmp = contramap age intCmp
fstCmp :: Comparison a -> Comparison (a, b)
fstCmp compA = contramap fst compA
```

Nothing new here. Let’s have a look at how to sort numbers. We use the `sortBy`

function defined in `Data.List`

from the `base`

package:

`sortBy :: (a -> a -> Ordering) -> [a] -> [a]`

We can see from the sortBy function definition that it can accept the data wrapped in the `Comparison`

data type:

```
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
getComparison :: a -> a -> Ordering
```

Sorting numbers with the above function:

```
-- unsortedNumbers = [3, 5, 1, 4, 2]
-- ascending sort
sortBy (getComparison intCmp) unsortedNumbers
-- [1,2,3,4,5]
-- descending sort
sortBy (flip $ getComparison intCmp) unsortedNumbers
-- [5,4,3,2,1]
```

Notice how we just use the flip function to change between ascending and descending sort:

`flip :: (a -> b -> c) -> b -> a -> c`

`flip`

just changes the order of input parameters. `flip`

is awesome :) I saw this technique first used at Roman Cheplyaka’s blog.

But here’s something interesting: since we know how to sort `Int`

s we also know how to sort people by age via `personAgeCmp`

! Let’s see that in action:

```
-- unsortedPeople = [Person "Tuvok1" 240, Person "Janeway" 40, Person "Neelix" 60]
-- ascending sort
sortBy (getComparison personAgeCmp) unsortedPeople
-- [Person {name = "Janeway", age = 40},Person {name = "Neelix", age = 60},Person {name = "Tuvok1", age = 240}]
-- descending sort
sortBy (flip $ getComparison personAgeCmp)
-- [Person {name = "Tuvok1", age = 240},Person {name = "Neelix", age = 60},Person {name = "Janeway", age = 40}]
```

A regular function can be though of being defined as:

`newtype RegularFunc a b = RegularFunc { getRegular :: a -> b }`

We can define a `Functor`

instance for `RegularFunc`

because `b`

is in output position. But what about `a`

, which is in input position? More on that below.

Let’s recall what the definition of the `Functor`

type class looks like:

```
class Functor f where
fmap :: (a -> b) -> f a -> f b
```

In the above declaration, `f`

is a type constructor with one type hole. Given `RegularFunc`

which has two type holes (`a`

and `b`

), we need to fill one in, in order to use it with the `Functor`

instance implementation. To do this we fix `a`

and get the type constructor `RegularFunc a`

. We can’t fix `b`

as partial application of types is done from left to right (holes can only be on the right).

```
instance Functor (RegularFunc a) where
fmap :: (b -> c) -> f b -> f c
fmap = (.)
```

We can’t define a `Contravariant`

instance for `a`

because we have to fix `a`

(we can’t define behaviour over it). All we have to play with is `b`

which is in output position (and hence covariant)

Oh! Come on! If only we didn’t have to fix `a`

. What if we could fix `b`

instead? We don’t care about `b`

. `b`

is dead to us.

Let’s dream up such a type and call it `Op`

- for **op**posite of regular:

`newtype Op a b = Op { getOp :: b -> a }`

Now we can see that the type `b`

is in input position within the data type. It’s also on the right of `Op a b`

which means we don’t have to fix it.

`Op a b`

can be a little confusing because we have switched the position of type parameters `a`

and `b`

as they were in `RegularFunc`

; `a`

is the output and `b`

is the input.

Data type | Polarity of a | Polarity of b |
---|---|---|

RegularFunc a b | Input | Output |

Op a b | Output | Input |

And guess what? We can now fix `a`

(which is now our output) and can define a `Contravariant`

instance for `Op`

:

```
instance Contravariant (Op a) where
contramap :: (c -> b) -> Op a b -> Op a c
contramap cToB (Op bToA) = Op $ \c ->
let b = cToB c
in bToA b
```

Here’s a simple example of how to use it:

```
stringsLength :: Op Int [String]
stringsLength = Op $ sum . fmap length
unqiueStringsLength :: Op Int (S.Set String)
unqiueStringsLength = contramap S.toList stringsLength
```

If we know how to sum all the lengths of a `[String]`

we can adapt that function to sum the lengths of a `Set`

of `String`

:

```
import Data.Set (fromList)
namesList = ["Paris", "Kim", "B'Elanna", "Seven"]
namesSet = fromList namesList
getOp stringsLength $ namesList
-- 21
getOp unqiueStringsLength $ namesSet
-- 21
```

Now `Predicate`

, `Comparison`

, `Equivalence`

and `Op`

seem like useful data structures. The good news is that they already exist in the Data.Functor.Contravariant package from `base`

so you don’t have to write them yourself.

One interesting implementation detail of the `Comparison`

and `Equivalence`

`Contravariant`

instances is that they are implemented using the `on`

function:

```
newtype Equivalence a = Equivalence { getEquivalence :: a -> a -> Bool }
instance Contravariant Equivalence where
contramap f g = Equivalence $ on (getEquivalence g) f
```

The `on`

function is defined as:

```
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
(.*.) `on` f = \x y -> f x .*. f y
```

Essentially given a function `b -> b -> c`

and a function `a -> b`

, the second function will be applied to each input of type `a`

converting it to a `b`

and then the first function is applied on the transformed inputs. Such reuse. :)

Let’s take a look at the `CallbackRunner`

example from FP Complete:

```
newtype CallbackRunner a =
CallbackRunner {
runCallback :: (a -> IO ()) -> IO ()
}
```

Type variable `a`

is in input position so we should be able to write a `Contravariant`

instance for it:

```
instance Contravariant CallbackRunner where
contramap :: (a -> b) -> CallbackRunner b -> CallbackRunner a
contramap aToB (CallbackRunner runCallbackB) = CallbackRunner $ \aToIO ->
runCallbackB $ \b ->
let a = undefined -- where do we get an `a` from?
in aToIO a
-- if we had a (b -> a) we could convert the `b` to an `a`
```

Hmm. Now it looks like we have a problem. There doesn’t seem to anyway for us to get an `a`

to pass to `aToIO`

to complete the implementation. We have a `b`

and if there was a function `b -> a`

instead of our `a -> b`

, we could convert that `b`

to an `a`

and it would all work.

This is because there’s more to the polarity story than I’ve shared up until now. While `a`

is in input position in `a -> IO()`

, it’s polarity changes when it’s also used as an input to the function `(a -> IO ()) -> IO ()`

. I previously mentioned that an input position is a `negative`

polarity and an output position is a `positive`

polarity.

To figure out the final polarity of something we need to multiply its polarities at every context it is used within in the function definition. More on this below.

Polarity multiplication is similar to the multiplication of positive and negative numbers:

Polarity1 | x | Polarity2 | Polarity |
---|---|---|---|

Positive | x | Positive | Positive |

Positive | x | Negative | Negative |

Negative | x | Positive | Negative |

Negative | x | Negative | Positive |

Let’s try and figure out the polarity of `a`

given our new found multiplication skills. Given `runCallback`

:

`runCallback :: (a -> IO ()) -> IO ()`

`a`

is in input or negative position in:

`a -> IO ()`

but within whole function it’s a slightly different story:

```
(a -> IO ()) -> IO () -- func
x = (a -> IO ()) -- assigning (a -> IO ()) to x in func
x -> IO () -- substituting x in func
```

We can see that `x`

in the above example is in input or negative position as well. Given that `x`

is `a -> IO ()`

:

```
(a -> IO ()) -> IO ()
-- a -> IO (a is negative)
-- (a -> IO ()) -> IO () (the whole parenthesis are in negative position)
-- polarity of a: negative * negative = positive
```

Given that `a`

is now in output or positive position, we should be able to write a `Functor`

instance for it:

```
instance Functor CallbackRunner where
fmap :: (a -> b) -> CallbackRunner a -> CallbackRunner b
fmap aToB (CallbackRunner runCallbackA) = CallbackRunner $ \bToIO ->
runCallbackA $ \a ->
let b = aToB a
result = bToIO b
in result
```

And we can!! If you want to dig more into polarities there are some good exercises at the FP Complete article.

We briefly mentioned invariant functors when talking about Polarity but never mentioned them again until now. The `Invariant`

typeclass is the parent typeclass of both `Functor`

and `Contravariant`

)

Given that this post is quite long, I’m only going to mention that `Invariant`

has both covariant and contravariant functions in its definition:

```
class Invariant f where
invmap :: (a -> b) -> (b -> a) -> f a -> f b
```

where `a -> b`

is the function to use if `f a`

is a `Functor`

and `b -> a`

is the function to use if `f a`

is `Contravariant`

.

I may write another article about invariant functors if I feel the need for it, but in the meantime checkout these articles to get you started.

Hopefully this has shed some light onto contravariant functors and how they are used and how they can be implemented. In a future article I hope to cover `Divisible`

and `Decidable`

typeclasses that build up from `Contravariant`

.

The source for this article can be found on Github.

A big “Thank You” to George Wilson for inspiring me to dig deeper into this topic with his excellent presentations on Functors.

A big thanks also to Andrew Newman who reviewed this article.

Just when you thought you’d learned all there is to learn about variance, there appears to be a variance of the fourth kind. It’s known as phantom variance or bivariance as pointed by emilypii and dbramucci on reddit. dbramucci also linked to a nice Scala slidedeck from Michael Pilquist

- Functor Optics - Oleg’s Gists
- 24 days of Hackage - Contravariant - Ocharles
- Covariance and Contravariance - FP Complete
- Understanding Contravariance - Type classes
- CO-LOG - Kowainik

- The Extended Functor Family - George Wilson
- Contravariant Functors - The Other Side of the Coin - George Wilson
- Fun with Profunctors - Phil Freeman
- A Fistful of Functors - Itamar Ravid

- Looking for an abstraction to compose - Reddit
- datafunctorcontravariant some simple applications - Reddit
- The motivation behind Contravariant - Reddit

A data type that needs one or more type variables to be fully defined.

For example, `Maybe`

is a type constructor and `Maybe Int`

is a type.

The Zen parable about **The glass that is already broken** reminds us of this beautifully:

You see this goblet? For me this glass is already broken. I enjoy it. I drink out of it. It holds my water admirably, sometimes even reflecting the sun in beautiful patterns. If I should tap it, it has a lovely ring to it. But when I put this glass on a shelf and the wind knocks it over, or my elbow brushes it off the table and it falls to the ground and shatters, I say, ‘Of course.’ When I understand that this glass is already broken, every moment with it is precious. Every moment is just as it is, and nothing need be otherwise.

Enjoy every moment.

]]>`stack ghci`

from the root of your Stack project.

This however does not include any test sources or dependencies you may have. To include those as well run:

`stack ghci --test --no-load`

]]>From within GHCi, enclose your function between `:{`

and `:}`

strings.

For example:

```
:{
printAfter :: Int -> IO ()
printAfter delay = do
putStrLn $ (\d -> "waiting for " ++ d ++ " microseconds") $ show delay
Control.Concurrent.threadDelay delay
putStrLn "done"
:}
```

If you can’t be bothered to add the opening and closing braces or you don’t need nice formatting, you can smash the whole function on one line by replacing every newline with a `;`

:

`printAfter :: Int -> IO (); printAfter delay = do; putStrLn $ (\d -> "waiting for " ++ d ++ " microseconds") $ show delay; Control.Concurrent.threadDelay delay;putStrLn "done"`

And that’s it!

]]>For the purposes of Milo, I wanted to access the latest direct messages for my user. Unfortunately the call to get your direct messages may return multiple pages of “empty” results and a cursor to the next page of results. I wanted to navigate these empty results and grab the first page with any results that were not empty - essentially just the latest direct message(s).

An example of an empty result:

```
{
"next_cursor": "some_hash",
"events": []
}
```

An example of a non-empty result:

```
{
"next_cursor": "some_hash",
"events": [
{ "id": "110", "created_timestamp": "5300", ... },
{ "id": "109", "created_timestamp": "5200", ... },
{ "id": "108", "created_timestamp": "5200", ... },
{ "id": "107", "created_timestamp": "5200", ... },
{ "id": "106", "created_timestamp": "5100", ... },
{ "id": "105", "created_timestamp": "5100", ... },
...
]
}
```

As we can see, the resulting Json payload has both the result (contents of the `events`

field) and the cursor (`next_cursor`

).

*Please note that I use Aeson to convert the Json payload into the DirectMessages data type used in the example, but I have omitted the bindings for clarity. The full Milo source can be found on Github.*

I initially came up with this solution:

```
import qualified Data.Text as T
-- Wrapper around the hash return by the Twitter API
newtype Cursor = Cursor { unCursor :: T.Text } deriving Show
-- Data type to hold the list of direct messages and the cursor (if any)
-- Each DirectMessage maps to a single element in the `events` array
data DirectMessages = DirectMessages { messages :: [DirectMessage], cursorPosition :: Maybe T.Text } deriving Show
-- Function that returns the direct messages or an error
getDirectMessages :: IO (Either String DirectMessages)
getDirectMessages = getMoreDirectMessages Nothing
-- Function that loops through the result pages using a cursor
getMoreDirectMessages :: Maybe Cursor -> IO (Either String DirectMessages)
getMoreDirectMessages nextCursor = do
dmsE <- callTwitterApi nextCursor
case dmsE of
Right dms@(DirectMessages messageList (Just nextCursor')) ->
if (null messageList) then -- if the messages are empty try to get more
do
(fmap (combineDms dms)) <$> (getMoreDirectMessages (Just . Cursor $ nextCursor'))
else pure . Right $ dms
Right dms@(DirectMessages _ Nothing) -> pure (Right dms) -- No more cursors so just stop
Left dmError -> pure . Left $ dmError
-- Function that collates direct messages
combineDms :: DirectMessages -> DirectMessages -> DirectMessages
-- Function that calls the Twitter API with the cursor (if any)
callTwitterApi :: Maybe Cursor -> IO (Either String DirectMessages)
```

Now while this works it has a few problems:

- It does not look very reusable, which it should be because pagination is a common problem
- There are dangling error cases where we just lift the error into some outer context

At this point I recalled seeing a function called `unfold`

somewhere that produced values until some exit condition was reached. I decided to track it down. I found unfoldr which sort of fitted what I needed.

`unfoldr :: (a -> Maybe (b, a)) -> a -> [b]`

From the docs:

The unfoldr function is a `dual’ to foldr: while foldr reduces a list to a summary value, unfoldr builds a list from a seed value. The function takes the element and returns Nothing if it is done producing the list or returns Just (b,a), in which case, b is a prepended to the list and a is used as the next element in a recursive call.

This sounded promising. I needed to keep “producing” direct message results and stop as soon as I got some results that were not empty. Unfortunately I needed to work within an effect (`IO`

) which this function did not support.

In any event let’s try and understand how this function works. This is the implementation of the the `unfoldr`

function:

```
unfoldr :: (a -> Maybe (b, a)) -> a -> [b]
unfoldr f a =
case f a of
Just (b,new_a) -> b : unfoldr f new_a
Nothing -> []
```

Given some generator function `f`

that takes a value of type `a`

, call `f`

with `a`

which returns a `Maybe`

with a pair of values consisting of a result `b`

and the next value of `a`

to feed into the same function. The `Maybe`

is either a `Just`

value with a new result `b`

and the next value of `a`

: `new_a`

. In this case the result `b`

is prepended to a list of results which will be generated by recursively calling the `unfoldr`

function with `f`

and `new_a`

. In the `Nothing`

case return an empty List.

Here’s a simple example that produces numbers from 1 to 10 and then stops:

```
import Data.List (unfoldr)
unfoldr (\a -> if a < 11 then Just (a, a + 1) else Nothing) 1
> [1,2,3,4,5,6,7,8,9,10]
```

Pretty neat but not what I exactly needed.

After some more digging around I stumbled across a library called monad-loops which had what I was after.

`unfoldrM :: Monad m => (a -> m (Maybe (b, a))) -> a -> m [b]`

We can see from its function definition that it’s exactly the same as `unfoldr`

except the intermediate and final results are within some `Monad m`

:

```
unfoldrM :: Monad m => (a -> m (Maybe (b, a))) -> a -> m [b]
unfoldr :: (a -> Maybe (b, a)) -> a -> [b]
```

This is the implementation of the `unfoldrM`

function (which is an alias to `unfoldrM'`

):

```
unfoldrM' :: (Monad m, MonadPlus f) => (a -> m (Maybe (b,a))) -> a -> m (f b)
unfoldrM' f = go
where go a = do
x <- f a
case x of
Nothing -> return mzero
Just (b, new_a) -> do
rest <- go new_a
return (return b `mplus` rest)
```

The implementation is very similar to `unfoldr`

with differences due to the selected effect type `m`

and result type `f`

.

Given some generator function `f`

that takes a value of type `a`

, it calls `f`

with `a`

within a `do`

block. It returns a `Maybe`

with a pair of values; the result `b`

and the next value of type `a`

: `new_a`

, within a context `m`

. It extracts and pattern matches on the contextual result. If it’s a `Nothing`

it returns the default value for the MonadPlus type `f`

(`mzero`

). If the result is a `Just`

, it creates a nested `do`

block and recurses with the `new_a`

value to extract the final result `rest`

. It then combines the `rest`

with the previous result `b`

according to the `mplus`

implementation for the `MonadPlus`

type `f`

and returns the results in the context `m`

. `unfoldrM`

is a specialized version of `unfoldrM'`

where `f`

is a `[]`

.

Now while this seemed to be what I needed it took a little while for me to understand how to use it in my use case. One thing that stumped me was why the initial value `a`

was not a `Maybe`

. Surely the first time I called the Twitter API, I would not have a cursor, so how could I represent it as an `a`

? Even if I did make `a`

a `Maybe a`

, how would I distinguish between the initial call where I had no cursor and the final call where I would also have no cursor?!

My friend Adam stated the obvious so I could understand it:

Maybe does not satisfy your requirements because you need more than two states

Oh dear! Was I supposed to create some ADT with three states? I thought this was supposed to be some plug-and-play solution and it was turning out not to be.

I started off by creating the ADT for the states:

```
-- | An ADT to capture the three states of a cursor:
data CursorState a
= NewCursor -- NewCursor - Initial cursor state
| GoCursor (Cursor a) -- GoCursor - A state of having a cursor, typically used for iteration
| StopCursor -- StopCursor - The final cursor state
```

Now if I plug in my types into the `unfoldrM`

function I get the following:

```
unfoldrM (a -> m (Maybe (b, a))) -> a -> m [b]
-- 'a' is CursorState c
-- 'c' is the type of cursor data
unfoldrM :: (CursorState c -> m (Maybe (b, CursorState c))) -> CursorState c -> m [b]
-- 'm' is IO
unfoldrM :: (CursorState -> IO (Maybe (b, CursorState c ))) -> CursorState c -> IO [b]
-- 'b' is DirectMessages
unfoldrM :: (CursorState c -> IO (Maybe (DirectMessages, CursorState c))) -> CursorState c -> IO [DirectMessages]
```

Now this seems to make sense.

Given that I already had a function of type:

`callTwitterApi :: Maybe Cursor -> IO (Either String DirectMessages)`

How could I convert it to work with the above function definition?

I could define a function `unfoldWith`

as:

```
unfoldWith :: forall m b c. CursorState c -> m (Maybe (b, CursorState c))
unfoldWith NewCursor = undefined
unfoldWith (GoCursor (Cursor nextCursor)) = undefined
unfoldWith StopCursor = undefined
```

The simplest one to define is the `StopCursor`

variant:

```
unfoldWith :: forall m b c. Applicative m => CursorState c -> m (Maybe (b, CursorState c))
unfoldWith NewCursor = undefined
unfoldWith (GoCursor (Cursor nextCursor)) = undefined
unfoldWith StopCursor = pure Nothing
```

and that compiles!

Next I can tried to implement the `NewCursor`

variant:

```
unfoldWith :: forall m b c. Applicative m => CursorState c -> m (Maybe (b, CursorState c))
unfoldWith NewCursor = undefined -- I need to be able to use callTwitterApi here
unfoldWith (GoCursor (Cursor nextCursor)) = undefined
unfoldWith StopCursor = pure Nothing
```

generalising the `callTwitterApi`

function:

```
callTwitterApi :: Maybe (Cursor c) -> IO (Either String DirectMessages)
-- Since we need to reduce our Monad to an m, wrap the IO (Either String) in ExceptT
-- ExceptT String IO is 'm' (Essentially a wrapped (IO Either String))
-- DirectMessages is 'a'
callTwitterApi :: Maybe (Cursor c) -> ExceptT String IO DirectMessages
-- which simplifies to:
callTwitterApi :: Maybe (Cursor c) -> m DirectMessages
-- Now we should be able to define any API that gets some `a` as:
someApi :: Maybe (Cursor c) -> m a
-- passing in someApi to unfoldWith
unfoldWith :: forall m a b c. Applicative m => (Maybe (Cursor c) -> m a) -> CursorState c -> m (Maybe (b, CursorState c))
unfoldWith f NewCursor = f Nothing -- call it with Nothing because we don't have a Cursor
unfoldWith f (GoCursor (Cursor nextCursor)) = undefined
unfoldWith _ StopCursor = pure Nothing
```

So far so good. But now we need to extract the result and the next cursor from response of the api call. When we call `someApi`

we get a `m a`

in return:

`someApi :: Maybe (Cursor c) -> m a`

*Note: To add type annotation to let expressions you need to enable the ScopedTypeVariables language extension*:

`{-# LANGUAGE ScopedTypeVariables #-}`

We need a function that transforms that `a`

into a pair of `(b, CursorState c)`

:

`extractPayload :: a -> (b, CusorState c)`

passing that into our `unfoldWith`

function:

```
unfoldWith :: forall m a b c. Applicative m => (a -> (b, CursorState c)) -> (Maybe (Cursor c) -> m a) -> CursorState c -> m (Maybe (b, CursorState c))
unfoldWith extractPayload callApiWith NewCursor =
let resultM :: m a = callApiWith Nothing
in Just . extractPayload <$> resultM
unfoldWith extract callApiWith (GoCursor (Cursor nextCursor)) = undefined
unfoldWith _ _ StopCursor = pure Nothing
```

Seems to compile. Now we do the same of the `GoCursor`

case:

```
unfoldWith :: forall m a b c. Applicative m => (a -> (b, CursorState c)) -> (Maybe (Cursor c) -> m a) -> CursorState -> m (Maybe (b, CursorState))
unfoldWith extractPayload callApiWith NewCursor =
let resultM :: m a = callApiWith Nothing
in Just . extractPayload <$> resultM
unfoldWith extract callApiWith (GoCursor (Cursor nextCursor)) =
let resultM :: m a = callApiWith (Just nextCursor)
in Just . extractPayload <$> resultM
unfoldWith _ _ StopCursor = pure Nothing
```

A `DirectMessages`

is defined as:

`data DirectMessages = DirectMessages { messages :: [DirectMessage], cursorPosition :: Maybe T.Text } deriving Show`

And now I just define a function that takes in a `DirectMessages`

type and returns a pair of `([DirectMessage], CursorState T.Text)`

:

```
extractState :: DirectMessages -> ([DirectMessage], CursorState T.Text)
extractState (DirectMessages [] (Just c)) = ([], GoCursor (Cursor c)) -- No messages, but we have a cursor, then try to get more
extractState (DirectMessages [] Nothing) = ([], StopCursor) -- No messages and no cursor, then stop
extractState (DirectMessages msgs _) = (msgs, StopCursor) -- Messages so we can stop irrespective of the cursor
```

Now I can call `unfoldrM`

with:

```
import qualified Control.Monad.Except as Ex
callTwitterApi :: Ex.ExceptT String IO DirectMessages
getDirectMessages :: IO (Either String DirectMessages)
getDirectMessages = Ex.runExceptT $ unfoldrM (unfoldWith extractState callTwitterApi) NewCursor
```

and we have pagination!

*Note how we had to unwrap the ExceptT with Ex.runExceptT to retrieve the wrapped IO (Either String DirectMessages)*.

The interesting point is that we now have a reusable function `unfoldWith`

which we can use with any paginated API that returns us a payload with a result and a cursor.

If you got a little lost in the details of the above example, don’t worry. Here’s a simpler example to give you some intuition.

```
-- Payload type
data Packet = Packet { value :: String, cursor :: Maybe (Cursor Int) }
-- Function that mimicks a server response
serviceCall :: forall m . Applicative m => Maybe (Cursor Int) -> m Packet
serviceCall Nothing = pure $ Packet "packet one" (Just $ Cursor 1)
serviceCall (Just (Cursor cur))
| cur == 1 = pure $ Packet "packet two" (Just $ Cursor 2)
| cur == 2 = pure $ Packet "packet three" (Just $ Cursor 3)
| cur == 3 = pure $ Packet "packet four" (Just $ Cursor 4)
| otherwise = pure $ Packet "packet five" Nothing
-- Function that splits the payload into a result and the next CursorState
extractState :: Packet -> (String, CursorState Int)
extractState (Packet v (Just c)) = (v, GoCursor c)
extractState (Packet v Nothing) = (v, StopCursor)
```

As before we can use it with:

`unfoldrM (unfoldWith extractState serviceCall) NewCursor`

Using the above to log out the first three page responses:

```
import Control.Monad.Loops (unfoldrM)
import Data.List (intercalate)
run :: IO ()
run =
let resultsIO :: IO [String] = unfoldrM (unfoldWith extractState serviceCall) NewCursor
stringyfied :: IO String = (intercalate "," . take 3) <$> resultsIO
in stringyfied >>= putStrLn
```

which prints out:

`packet one,packet two,packet three`

I’m not sure if this is a “pattern” that people generally use but I can see myself using this for other paginated APIs.

The code for the Simpler Example.

]]>