1. 19
jackkelly.name
1.

2. 1

Small Remark: Personally I would move the chaining of Transforms to within the data type (so add `| Chain [Transform]` to `Transform`). I think this would improve composability of transformations and also remove the need for the `transform`-function since in `toMatrix` and `toCodeWorld` you could then just directly pattern match on the `Transform`-type.

Other than that a very nice article showing a nice use case of why to prefer data over functions.

1. 1

I’m unsure exactly what you’re suggesting. Can you please elaborate, perhaps by providing a full definition of the `Transform` type that you had in mind?

1. 2

Something like:

``````data Transform
= Scale Double Double
| Translate Double Double
| Chain [Transform]
``````

Then the function `toMatrix` would for example become:

``````toMatrix :: Transform -> M33 Double
toMatrix (Scale x y) = V3
(V3 x 0 0)
(V3 0 y 0)
(V3 0 0 1)
toMatrix (Translate x y) = V3
(V3 1 0 x)
(V3 0 1 y)
(V3 0 0 1)
toMatrix (Chain ts) =
foldr ((!*!) . toMatrix) identity ts
``````
1. 1

Thanks, but I disagree with this, for a couple of reasons: first, it makes `Transform` into an N-ary tree with leaves of `Scale` and `Translate`, but a tree doesn’t match the thinking we’re trying to capture: a linear sequence of transformations that can be applied to something later. Second, you lose the nice connection to the free monoid, which means that concerns about structuring multiple transformations are now intermingled with the specification of a single transformation.

If the calls to `transform` are too much syntactic noise, then I’d rather write this:

``````toMatrix :: [Transform] -> M33 Double
toMatrix = foldr ((!*!) . toMatrix') identity
where
toMatrix' (Scale x y) = V3
(V3 x 0 0)
(V3 0 y 0)
(V3 0 0 1)
toMatrix' (Translate x y) = V3
(V3 1 0 x)
(V3 0 1 y)
(V3 0 0 1)
``````