4 ms·
It seems to me that this article actually proves the opposite point that it's trying to make. I have no idea what the program presented is supposed to do, or w
by jlarocco 13y ago
It seems to me that this article actually proves the opposite point that it's trying to make.
I have no idea what the program presented is supposed to do, or what problem is being solved, despite knowing all the types being used.
I swear the point of Haskell is to make people using Haskell feel smart :-)
- Guvante 13y agoA simpler example would be a basic list operator, given a method you can guess what it does. [a] -> a That takes a list (brackets denote a linked list) and returns a single item. There is a small list of things that this could be. It can't filter or order in any way, since there are no restrictions or functions provided, it can't aggregate for the same reason, that leaves either the first item or the last item. [Yep head and last](http://www.haskell.org/hoogle/?hoogle=%5Ba%5D+-%3E+a http://www.haskell.org/hoogle/?hoogle=%5Ba%5D+-%3E+a) Looking at that list we can see some other alternatives that I mentioned foldl1 :: (a -> a -> a) -> [a] -> a --Aggregation maximumBy :: (a -> a -> Ordering) -> [a] -> a --Ordering maximum :: Ord a => [a] -> a (!!) :: [a] -> Int -> a --Indexing sum :: Num a => [a] -> a --Aggregating product :: Num a => [a] -> a And if followed along, you will notice all of his implementation points were straightforward. Note that all of this assumes you have very well written APIs that follow this chain of logic, otherwise you can write things like this. second :: [a] -> a second _:i:_ = i It compiles (or would with the default case added) but is rather odd and would throw off this line of reasoning. Similarly by abusing unsafe methods you can do crazy things.
- nandemo 13y agoYour function second is no worse than head or last. I think you chose a difficult example. [a]->[a] or a->a would be simpler, if a bit boring.
- Guvante 13y agoI dunno, I like second being a bad choice, the number of times it is useful are very few. `!! 2` is much more straightforward. In contrast `last` is impossible to do that way and `head` is part of the underlying data structure (as in it is a linked list, so has head and tail) so is a gimme.
- jlarocco 13y ago> It can't filter or order in any way, since there are no restrictions or functions provided, it can't aggregate for the same reason, that leaves either the first item or the last item. That doesn't logically follow. Technically it can return any item in the list. Without some kind of documentation there's no way to know. Saying "you can guess what it does" doesn't buy me anything over any other language. I can guess what a function does in C or C++, too, and in my experience I'll guess right in C and C++ more often than I will in Haskell.
- Guvante 13y ago> Technically it can return any item in the list But that is all it can return. By looking at the name I know with 100% certainty what it is. > I can guess what a function does in C or C++, too Never without the name. Too few functions are actually pure and the difference in a pure signature and a non-pure one doesn't exist. Heck if it is C or C++ it could cast all the void* to int* and find the first one that is non-null and points to a positive value.
- dragonwriter 13y ago> [a] -> a > That takes a list (brackets denote a linked list) and returns a single item. There is a small list of things that this could be. It can't filter or order in any way, since there are no restrictions or functions provided, it can't aggregate for the same reason, that leaves either the first item or the last item. Assuming that lists can be empty, it can't be the first item or last item either, as either of those (or the second, or third, etc.) would have to be [a] -> Maybe a Haskell doesn't actually do this, but (while there may be pragmatic reasons to do this and yet have them work on a type that isn't constrained to non-empty lists), its kind of a failure in the logic of types, which makes head (and last, etc.) subject to crashing. But if you pretend that you can use type based logic and what is possible to guarantee based on the type signature to infer semantics of returned values, then you have to really follow the logic alone -- if you can start to accept that there could be unstated assumptions of the type Haskell actually makes, then you open up lots of other possibilities based on which specific unstated assumptions that aren't implicit in the types involved are made.
- chowells 13y agoI suppose it is a bit ironic that I chose to build a library that really does benefit from higher-level explanation. That's what happens when you build software engineering tools - you have to convince programmers of their value, even if they see how to use them.
- sacundim 13y ago"I have no idea what the program presented is supposed to do, or what problem is being solved, despite knowing all the types being used." This is an absolutely fair observation. The code being shown is basically chowells79's recreation of a library that I wrote about a year ago: http://hackage.haskell.org/package/free-operational http://hackage.haskell.org/package/free-operational Basically, it really only makes sense once you've studied and grasped the key ideas behind a handful of other things: (a) functors, applicatives and monads; (b) the `operational` monad (another library, which mine recreates and expands on); (c) free monads (yet another library). If you look at the link above, you'll note that I've chosen to follow the opposite approach—I provide links to other sources that provide the background context for what the library is doing. Elsewhere in the documentation I provide extended (but toy) examples of how to use it, of which I'd highlight the one in here: http://hackage.haskell.org/package/free-operational-0.5.0.0/docs/Control-Alternative-Operational.html http://hackage.haskell.org/package/free-operational-0.5.0.0/... That page's example demonstrates a toy implementation of parser combinators and three different ways of using it: (a) parsing strings, (b) enumerating the strings that a parser accepts, and (c) optimizing parsers by merging paths with common prefixes. So basically, the library is a kind of interpreter construction toolkit. A very abstract one...