Consider this function:
doToBoth f x y = (f x, f y)
It works as expected in simple cases:
doToBoth (2 *) 10 15 == (20, 30)
doToBoth head [1,2] [3,4,5] == (1, 3)
Then I tried these ones:
doToBoth head [1,10,100] "apple"
doToBoth pred 2 'b'
I want those to both result in (1, 'a'), but instead they just result in a type error. The problem is that the inferred type of doToBoth isn't polymorphic enough:
doToBoth :: (a1 -> a2) -> a1 -> a1 -> (a2, a2)
Seeing this, I tried adding an explicit type signature to fix it:
doToBoth :: (t ~ (i1 -> o1), t ~ (i2 -> o2)) => t -> i1 -> i2 -> (o1, o2)
This type signature was accepted, but it didn't fix the problem, and checking what happened with :t doToBoth revealed that it ended up with a type equivalent to the original inferred one:
doToBoth :: (i2 -> o2) -> i2 -> i2 -> (o2, o2)
What is the correct way to write a type signature to make this function work the way I want?
headfunction (I can edit either or both of those into your answer there if you want). The only wart about it is that it doesn't really work on thelengthfunction, but rather on the functionlength . toList. I tried for a little while to fix that with the various new GHC extensions since you wrote that back in 2015, but with no luck.