0

Is there any way such that I can arbitrarily establish a partial order on a collection of functions.

That is, given two functions f,g; can I consistently evaluate f < g to some truth value.

Cole Comfort
  • 5
  • 1
  • 1
  • 6

2 Answers2

6

No. There is no way to compare functions to each other. You can't even evaluate f == g.

If you could do this (and you probably can, by eg reaching into IO to look up the functions' memory addresses), you would be violating referential transparency. Consider the following definitions:

f = (+) 2
g x = 2 + x

These two functions behave the same for all inputs, which means by referential transparency you can treat them interchangeably: foo f should be equal to foo g for any foo, and as a consequence foo f g should be the same as foo g f. But if we let foo be your (<) function, we would break this law. A lot of Haskell depends on referential transparency, so even if you can find some way to cheat around this I would encourage you not to.

But if you want to use IO, I think it is relatively harmless to write a function with the signature:

(<) :: a -> b -> IO Bool

by looking at the memory addresses of the two arguments.

amalloy
  • 89,153
  • 8
  • 140
  • 205
  • Even still, not by their actions, which is undecidable, but in some arbitrary way? – Cole Comfort May 20 '16 at 05:41
  • The only thing you can do with a function is evaluate it at a point. – Chris Martin May 20 '16 at 05:42
  • There are no unique identifiers of functions which are exposed to the Haskell language at all? – Cole Comfort May 20 '16 at 05:43
  • 3
    No. Unlike a lot of other languages, a function in Haskell is literally a function and nothing else. – Chris Martin May 20 '16 at 05:49
  • 1
    @ColeComfort, not even slightly. This means the compiler gets to tear them to shreds and put them back together inside out and backwards and no one will ever know the difference. It also makes reasoning about functions easier. – dfeuer May 20 '16 at 05:50
  • I want to be able to insert and remove functions along with some other data from a tree by the index of a function efficiently. Is there any other way to do this without using at IO? – Cole Comfort May 20 '16 at 05:55
  • Use something else as the key in your tree. For example, before you add a function to your tree you can assign it an arbitrary identifier, and then use that as the lookup key. – amalloy May 20 '16 at 05:57
  • 1
    I'm uncertain you could even do it with IO. – Louis Wasserman May 20 '16 at 05:58
  • @amalloy If I use a key, how could I extract an arbitrary function from the tree a priori the knowledge of the construction of the tree. – Cole Comfort May 20 '16 at 06:01
  • 1
    Comparing memory addresses will be far from consistent. The garbage collector can move things all over the place. – dfeuer May 20 '16 at 06:01
  • 1
    You can't, @ColeComfort. But when you insert a function into the tree, and generate an identifier for it, you also give back that identifier to whoever wanted the function inserted. And then they can keep track of it, and use it to get back their original data. – amalloy May 20 '16 at 06:03
  • And you don't need `IO` for such shenanigans. `reallyUnsafePtrEquality#` is the one that's actually useful sometimes. I don't know if comparison is possible at all. Maybe using `unsafeCoerce#` and coercing between a function type and an `Int#`? I don't know if you can, but you shouldn't! – dfeuer May 20 '16 at 06:05
  • @amalloy Is there any way to do this that would be particularly unintrusive, rather than plainly chaining around the tree? – Cole Comfort May 20 '16 at 06:05
  • 1
    @dfeuer I found http://stackoverflow.com/questions/18560833/how-to-print-memory-address-of-a-list-in-haskell, which looks like it would allow you to do comparisons, but it's not consistent because garbage collection can end up moving things around. – amalloy May 20 '16 at 06:07
  • My problem is answered here (I think) http://stackoverflow.com/questions/15272231/function-to-output-function-name – Cole Comfort May 20 '16 at 06:25
3

You kinda can. If in a -> b a is finite and b can be ordered, then all you need is to compare f x and g x for all x from a until f x /= g x. This is the same as comparing tuples, since a function from a finite a is isomorphic to an n-ary tuple.

effectfully
  • 12,325
  • 2
  • 17
  • 40
  • Yummy representable functors! – dfeuer May 20 '16 at 07:12
  • 1
    @dfeuer, the representable functors class is too big, isn't it? It includes coinductive types like `Stream`. Well, you can define an `Ord` instance for `Integer -> b` assuming `Ord b`, but `id < id` will loop. – effectfully May 20 '16 at 07:25
  • You can do better than finite though, I think. Won't well-founded do? – dfeuer May 20 '16 at 08:25
  • @dfeuer, you mean when `a` is enumerable in increasing order, `b` is strict total order with an infimum, and `f` and `g` are antitone? So if `Decreasing f` and `Decreasing g` where `Decreasing h = forall x. Either (h x = 0) (x < y -> h y < h x)`, then there is a `z` such that either `f z = 0` or `g z = 0` and we have the answer. E.g. having `f g :: Nat -> Nat; f n = 10 - n; g n = 15 - n` we can decide `f < g`, because `f 10 == 0` while `g 10 /= 0`. Or something like that. – effectfully May 20 '16 at 09:56
  • I lost track. Intuitively, it doesn't have to be finite as long as you can be sure to get to the bottom of it going down (classically well-founded). – dfeuer May 20 '16 at 15:25
  • @dfeuer, I meant that `a` doesn't need to be finite if `f` and `g` are such that when `x` increases `f x` and `g x` decrease (and `b` has an infimum). Then you need to inspect only a finite number of `x`s regardless of whether `a` is finite or not. – effectfully May 20 '16 at 16:53