PiotrLegnica

Equational reasoning

Feb 19th, 2013
21
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.53 KB | None | 0 0
  1. Step 1: let's define function composition.
  2. [code]compose f g x = f (g x)[/code]
  3. Nothing mind-bending here. The type is well-known:
  4. [code]compose :: (b -> c) -> (a -> b) -> a -> c[/code]
  5.  
  6. Step 2: let's see what happens when we pass compose as the first argument:
  7. [code]
  8. compose = \f g x -> f (g x)
  9. compose compose
  10. = \g x -> (\f' g' x' -> f' (g' x')) (g x) -- (g x) can be immediately substituted for f'
  11. = \g x -> \g' x' -> (g x) (g' x')
  12. = \g x -> \h y -> (g x) (h y) -- just renamed variables
  13. [/code]
  14. This results in a partial application of [fixed]compose[/fixed] with [fixed](g x)[/fixed] substituted in place of [fixed]f[/fixed].
  15.  
  16. We should try to figure out what happens with types. We know that both [fixed]g[/fixed] and [fixed]h[/fixed] are one-argument functions, and that [fixed]g[/fixed] returns one-argument function. We also know that the result of [fixed]h[/fixed] is used as an argument to function returned by [fixed]g x[/fixed].
  17.  
  18. [code]g :: (a' -> (b' -> c'))
  19. h :: (d' -> b')
  20. \h y -> (g x) (h y) :: (d' -> b') -> d' -> c' -- g and x are free variables
  21. [/code]
  22.  
  23. Because we're partially applying [fixed]compose[/fixed], we get this in result:
  24. [code]\g x -> (\h y -> (g x) (h y))[/code]
  25. and its type is
  26. [code](a' -> (b' -> c')) -> a' -> ((d' -> b') -> d' -> c')[/code]
  27. We can skip some of those parentheses because [fixed](->)[/fixed] is right-associative:
  28. [code](a' -> b' -> c') -> a' -> (d' -> b') -> d' -> c'[/code]
  29.  
  30. Let's check if GHC agrees:
  31. [code]
  32. [Prelude]
  33. > :t (\g x -> \h y -> (g x) (h y))
  34. (\g x -> \h y -> (g x) (h y))
  35. :: (t1 -> t2 -> t) -> t1 -> (t3 -> t2) -> t3 -> t[/code]
  36.  
  37. So far, so good!
  38.  
  39. Step 3: partially applying above to [fixed]compose[/fixed] again.
  40. [code]\x -> \h y -> (compose x) (h y)
  41. \x -> \h y -> ((\f' g' z -> f' (g' z)) x) (h y)
  42. [/code]
  43.  
  44. Oh gods, looks scary as hell. Let's collapse it a little before type checking — [fixed]x[/fixed] is immediately applied to that innermost lambda, so we'll pull [fixed]f'[/fixed] to the front:
  45.  
  46. [code]\f' -> \h y -> (\g' z -> f' (g' z)) (h y)[/code]
  47.  
  48. [fixed](h y)[/fixed] is immediately applied to that lambda, too:
  49.  
  50. [code]\f' -> \h y -> (\z -> f' ((h y) z))[/code]
  51.  
  52. Currying lets us skip the inner parentheses and collapse lambdas into one:
  53.  
  54. [code]\f' h y z -> f' (h y z)[/code]
  55.  
  56. I think it should be fairly obvious what the type of this function is.
  57.  
  58. [code][Prelude]
  59. > :t (\f' h y z -> f' (h y z))
  60. (\f' h y z -> f' (h y z))
  61. :: (t1 -> t) -> (t2 -> t3 -> t1) -> t2 -> t3 -> t[/code]
  62.  
  63. There you go, equational reasoning at its finest.
Advertisement
Add Comment
Please, Sign In to add comment