Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

This repo contains two related packages:

  • apply-unordered-mono, which uses type family / typeclass machinery to provide type-directed function application and argument reordering. It is severely restricted, in that it only supports monomorphic arguments and parameters.

  • apply-unordered, which uses similar machinery, but also provides a GHC plugin in order to support type-directed function application on polymorphic functions. The plugin uses the same logic as overlapping instances for resolving which parameter each argument should be passed to.

The didactic directory provides a few different versions of apply-unordered-mono, for explanatory purposes.


Example of use:

import Control.Apply.Unordered.Mono ((?), reorderArgs)

-- These will have the same value, "ccc", even though the arguments are
-- provided in a different order!

oneWay = replicateChar ? 'c' ? 3
otherWay = replicateChar ? 3 ? 'c'

replicateChar :: Int -> Char -> String
replicateChar = replicate

It also provides a function for type-directed re-ordering of arguments:

f1 :: A -> B -> C -> D

f2 :: C -> A -> B -> D
f2 = reorderArgs f1

I considered naming / categorizing this as an acme- package, since it's a mechanism that doesn't mesh well with Haskell's polymorphism. However, I've decided that someone might actually find this useful or interesting. Particularly:

  • It allows you to pass arguments to functions without remembering the argument order. If the function's argument order is permuted, your code will still work.

  • It probably usually optimizes away to 0 runtime overhead. I say "probably" because I have not benchmarked it or taken a look at the core. I did sprinkle INLINE pragmas everywhere, though.

  • Incorrect usage often results in decent type errors, via custom type error messages.


The goal of apply-ordered is to do this same unordered application, but in a way that is compatible with Haskell's polymorphism. Here's how it works:

  • Control.Apply.Positional provides an applyAt function which lets you write (applyAt @1 replicateChar 'c') 3. The @1 specifies the function parameter index to provide the argument to.

  • Control.Apply.Unordered.Plugin provides a GHC plugin that replaces occurrences of the type family BestParamIxImpl (a :: *) (f :: *) with a type level natural indicating the index of the parameter of f that best matches the argument type a. This "best matching" logic works exactly the same as matching the type parameters of overlapping instances.

  • Control.Apply.Unordered sticks BestParamIxImpl together with the applyAt machinery to yield a better ? function that can handle polymorphic functions!

This already seems to work well, but the code could use some more polish and testing.


Experiments in type-directed function application and argument reordering






No releases published


No packages published