7

While learning Haskell, I came across a challenge to find two functions f and g, such that f g and f . g are equivalent (and total, so things like f = undefined or f = (.) f don't count). The given solution is that f and g are both equal to \x -> x . x (or join (.)).

(I note that this isn't Haskell-specific; it can be expressed in pure combinatory logic as "find f and g such that f g = B f g", and the given solution would then translate to f = g = W B.)

I understand why the given solution works when I expand it out, but I don't understand how you'd ever find it if you didn't already know it. Here's how far I can get:

  • f g = f . g (given)
  • f g z = (f . g) z (eta-expansion of both sides)
  • f g z = f (g z) (simplify the RHS)

And I don't know how to proceed from there. What would I do next in trying to find a solution?

  • 2
    Perhaps one place to start is to work out what types they have to have. It turns out that for the expression to make sense, they have to have polymorphic types, which can tell you a lot about possible implementations. – luqui Jan 26 '19 at 04:07
  • 4
    Let `f` be `id` and `g` be any function. `id g = g = id . g`. – Rein Henrichs Jan 26 '19 at 04:07

1 Answers1

9

I discovered that it's possible to find a family of solutions by considering Church numeral calculation. In the Church encoding, multiplication is performed by composing the Church numerals, and exponentiation is performed by applying the base to the exponent. Thus, if f is the Church encoding of some number x, and g is the Church encoding of some number y, then f g = f . g implies y^x = x*y. Any nonnegative integer solutions to this equation translate to solutions to the original problem. Examples:

  • x=1, y=0, f=id, g=const id
  • x=1, y=1, f=id, g=id
  • x=1, y=2, f=id, g=join (.)
  • Since y^1 = y = 1*y for all y, it makes sense that f=id works for all Church numerals g. This is indeed the case, and in fact, as Rein Henrichs pointed out, it's true for all g, and this is easily verifiable by inspection.
  • x=2, y=0, f=join (.), g=const id
  • x=2, y=2, f=join (.), g=join (.)
  • x=3, y=0, f=(.) <*> join (.), g=const id
  • Since 0^x = 0 = x*0 for all positive x, it makes sense that g=const id works for all positive Church numerals f. (It does not work for f=const id, Church numeral 0, which makes sense since 0^0 is an indeterminate form.)