Functions are just boring implementation detail. The structures tell you everything.
From what I've seen, this is where people usually struggle when it comes to learning functional programming. People are so wrapped up in the algorithms that they have a hard time thinking in data in the way that is required to do functional programming effectively.
Agda[1] and Idris[2] turn this idea into interactive editing with typed holes. You put a "?" in the code and the compiler fills the hole in for you based on the type that it infers for it. Haskell has a less expressive type system but it also has typed holes and Wingman[3] extends the Haskell Language Server to use them for interactive editing.
[1] https://www.youtube.com/watch?v=bRudW0aBNg8
Is this true? I understand types are abstract, while data structures are concrete.
Like, the type...
x -> a x y -> z y
...tells me nothing. But that is, among many things, the type for a hash map lookup. Still, a hash map is a particular implementation, and the type alone doesn't capture this – it could mislead me into thinking any implementation that fits this shape is fine.
This is the actual type of Haskell's dictionary lookup:
k -> Map k a -> Maybe a
I don't know about you, but that's pretty self-explanatory to me.
That's only because you, the programmer, expect a type named "hash map" to implement a hash map – but this information is not being described by the type itself, it's out-of-band. The actual definition of the hash map data structure is given by the algorithm. In fact, without inspecting the algorithm, it's impossible to know it correctly implements a hash map, you're just trusting the arbitrary name of the type.
Depending on the language, no. In many languages types can be subtyped, and if you name the supertype you do not know necessarily which implementation you have. (Incidentally, in Haskell, a Map is not a HashMap, it is a tree map.)
> The actual definition of the hash map data structure is given by the algorithm. In fact, without inspecting the algorithm, it's impossible to know it correctly implements a hash map, you're just trusting the arbitrary name of the type.
This is exactly my point! The question we started with is: does the type signature help you to reason about how to transition from one data structure to another data structure without having to think about the details of the algorithm? I argue that it does, because I tend to trust that standard library designers aren't capriciously violating my expectations for what a Map is.
If you trust the standard library designers, then the type signature abstracts away the implementation details of the algorithm so you can do what Rob Pike recommends and focus on the data.
If you don't trust your language's standard library, you have worse problems than difficulty reasoning about type relations.
You don't even need to trust them. The compiler checks that their Map is the same as what you call a Map.
In the scenario that I am imagining, you have defined your data structures as types. You're looking for an algorithm to perform a particular transformation on your data. This transformation is from one data type to another, so you know the "type signature" of the algorithm. If the algorithm is already implemented, then you can find it with typed holes or Hoogle. If it doesn't exist yet, you can write it.
Rob Pike's Rule 5 says that if your types are good, it will be self-evident what functions to use to transform them.
Sort of. I think the person I was replying to was indicating that the implementation could be wrong and still match the type signature. As a simple example, `insert` could return the exact same Map object as was passed in (rather than one that has the key updated) and still match the type signature of `insert`.
On the whole you're right, because if your standard data structures are that bad you should really be using a different language, not choosing to ignore types because they might not be helpful this time.
> x -> a x y -> z y
> ...tells me nothing.
I am guessing that you wouldn’t see a type signature like this in a real codebase. The type signature of Data.HashMap.Strict.lookup is
(Eq k, Hashable k) => k -> HashMap k v -> Maybe v
which is quite a bit more readable. You can even search Hoogle for x -> HashMap x y -> y and find it, try it!https://hoogle.haskell.org/?hoogle=x%20-%3E%20HashMap%20x%20...
Not really. Types include datastructures. They define the set of values that a datastructure can assume. They do the same for everything else, like variables, functions etc.
Really, in practice this means data is a partially applied, curried, identity function. Put something in, get the same thing out later, acting as memoization.
Rule 5 of Rob Pike[1] says:
> Data dominates. If you've chosen the right data structures and organized things well, the algorithms will almost always be self-evident. Data structures, not algorithms, are central to programming.
which makes a lot of sense to me. You see this concept being used all over the place in Golang/Rust.
But functional languages make you think in very different ways, which makes your program organized in much different ways as well. Although I can't quite put my finger on what exactly is so different.
[1]: http://users.ece.utexas.edu/~adnan/pike.html