1

I'm reading a book Haskell Programming From First Principles. On p. 122 authors highlight fst function:

fst :: (a, b) -> a

The result of the function, which has type a. It’s the same a that was in the tuple (a, b). How do we know it’s the same a? We can say that we know the input type a and the output type a must be the same type, and we can see that nothing happens between the input and the output; that is, there is no operation that comes between them that could transform that a into some other value of that type.

Also earlier, p. 107, in reference to fst and snd:

The type signature tells us there’s nothing those functions could do other than return the first or second value, respectively.

I don't get this. If a had a typeclass constraint like Num a => (a, b) -> a the function could easily add 3 to the first argument of the tuple and return something of the same type a but a different value, and this would not show up in the type signature of the function. Is the point that you couldn't really do anything to the input tuple without some typeclass constraint? Or without knowing that the input is e.g. a list, as in tail :: [a] -> [a], by which we just know based on our knowledge of lists that tail could be adding or removing elements to/from the input? Even without a typeclass constraint, couldn't (a, b) -> a just return some arbitrary constant of type a, not necessarily the first element in the tuple?

How do the authors come to this conclusion?

tsj
  • 758
  • 3
  • 23
  • 3
    But it has no type constraint, hence there is no function like `+`, `-`, etc. that you can use. The only option would be `undefined` or a function that calls itself and thus gets stuck in an infinite loop, but that is non-sensical. See for example [*djinn*](https://www.hedonisticlearning.com/djinn/) that can for simple types exhaustively produce all possible functions. – Willem Van Onsem Mar 04 '22 at 13:22
  • I find this is a very interesting question. I hadn't ever thought about it, but I can't think of anything you can actualy do with a type without knowing what typeclasses it honors. (Clearly if you don't write the signature, the compiler will be able to infer what typeclass is needed.) – Enlico Mar 04 '22 at 13:22
  • 3
    The classic reference is [Theorems for free!](https://dl.acm.org/doi/10.1145/99370.99404) – leftaroundabout Mar 04 '22 at 13:25
  • 1
    Thanks for all the links, they are useful. I figured this was a dupe but couldn't come up with the right search. Really just the *Real World Haskell* quote from the other question clarifies it enough. – tsj Mar 04 '22 at 13:53
  • 2
    Regarding your `f :: [a] -> [a]` example: such a function can only discard or duplicate elements from the input. That is, `f [1,2,3]` can not return `[3,3,7,1]` because of the `7`. At best, it can introduce new "bottom" elements. Also, if `f [1,2,3]` is `[1,1,3]`, then `f "abc"` must be `"aac"`, since there is no way for `f` to act differently -- `f` can only "blindly move around" the values of type `a` without knowing what they actually are. – chi Mar 04 '22 at 14:27
  • 1
    "couldn't (a, b) -> a just return some arbitrary constant of type a" How would it get a constant of type `a`, without having any constraint about `a`? – Louis Wasserman Mar 04 '22 at 17:54
  • My thought was a lookup table based on the real type of `a`, but 1) that could never be comprehensive and 2) that information is not available anyway. – tsj Mar 04 '22 at 18:33

0 Answers0