tag:blogger.com,1999:blog-11788780.post5131957265387550855..comments2023-12-29T13:22:33.104-08:00Comments on JJinuxLand: Haskell: Syntaxjjinuxhttp://www.blogger.com/profile/03270879497119114175noreply@blogger.comBlogger37125tag:blogger.com,1999:blog-11788780.post-29607149064117745642011-02-10T15:44:29.830-08:002011-02-10T15:44:29.830-08:00A few points:
* You usually shouldn't have to...A few points:<br /><br />* You usually shouldn't have to think about currying, at all, except in specific circumstances. It is only when you deal with /pairs/ (a,b) as a single argument in a function that expects "two" arguments that currying is an issue. Partial function application deals with the "regular" f :: a -> b -> c case trasparently. f a b = (f $ a) $ b<br /><br />* Function application ($) is a big deal, especially when used with function composition, and partial function application (at least when the partial function is "naturally" typed the way you want). This lets you do things like:<br /><br />(^2) . (+2) . (sqrt) $ 4<br /><br />The $ is the "prompt" that takes you from a points free style to a pointed style. If you can handle a command line interface, you can write in this style. Sometimes the type inference engine isn't strong enough to infer a type unless you use an explicit argument, so knowing this style is helpful.<br /><br />* Functors are important, for similar reasons. We can use the <$> syntax instead of fmap, to write things like:<br /><br />(^2) . (+2) . sqrt <$> [1,2,3]<br /><br />* Anybody trying to tell you that there is a substantive difference between software development and mathematics is trying to sell you something. Software development is about finding the normal forms for the data structures and computations you wish to encode, and organizing the code in ways that don't obscure the normal form. This is first year OO textbook stuff. On the other hand, mathematicians have been doing exactly that for about 10,000 years, since the rise of the Indus Valley Civilization. We know a thing or two about finding minimal expressive normal forms, and organizing them. Don't patronize us.<br /><br />In fact, it is rather amazing that the alphabet of "funny symbols" is so small. Part of learning to do mathematics is to learn to ignore the funny symbols when it isn't necessary to understand them, and look at what they are <i>connecting</i>. That is far more informative.<br /><br />For example: what's important about the expression<br /><br />"shirts_in_factory_a + shirts_in_factory_b"?<br /><br />There is only one sensible way to combine these quantities. Clearly, this will be the expression that does it. Now, if you really need to dig deeper, you are welcomed (and hopefully capable) of digging into the semantics of (+) to verify it's doing what we expect (obviously, that should be unnecessary in the case of addition).<br /><br />Remember that the typical software development cycle spends far more time in the maintenance phase than the writing phase. Expressing minimal normal forms makes "refactoring" trivial, especially with the help of the type system (which will basically act as a check list of tasks to complete until the task is complete).<br /><br />* "What would happen if we didn't know the signature of unwords?"<br /><br />You type ":t unwords" into GHCi.<br /><br />You are acting as if this is somehow causing complexity. You would have the same problem in any other language. You are either composing functions of the right types with each other, or you have a bug. (Or you are writing in an imperative-OO style, instead of functional-OO, which is just bad for your sanity. Humans can only keep about 7 things in short term memory. You basically have 7 registers to do your mental computations with. There's no point filling them with the values of variables when you could be thinking about their types instead)Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-11788780.post-19148615705154631612009-02-25T00:36:00.000-08:002009-02-25T00:36:00.000-08:00Agreed. However, that isn't to say that I think H...Agreed. However, that isn't to say that I think Haskell syntax is perfect.jjinuxhttps://www.blogger.com/profile/03270879497119114175noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-7381340518383964222009-02-24T21:11:00.000-08:002009-02-24T21:11:00.000-08:00As a Haskell newbie, I find the concise syntax enh...As a Haskell newbie, I find the concise syntax enhances both readability and productivity. And a major bonus over Scheme.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-11788780.post-16738921197397241202008-06-05T17:18:00.000-07:002008-06-05T17:18:00.000-07:00I suggest that you avail yourself of liftM, liftM2...I suggest that you avail yourself of liftM, liftM2 etc and mapM and foldM whenever possible. They're especially useful for Maybe (or when you use Monad m => ... to represent that the receiving function chooses whether to get a Maybe or an exception or an Either String), since do and >>= don't represent the natural way of thinking about these for me. Naturally, for I/O do is the better option.Robert Furberhttps://www.blogger.com/profile/10746976399050925428noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-45370287243493590572008-01-17T10:37:00.000-08:002008-01-17T10:37:00.000-08:00like the parentheses in lisp (which i find horribl...like the parentheses in lisp (which i find horrible) the haskell syntax is what makes the language. i love it as lisp developers like there parentheses. for me it makes everything so much easier.duschendestroyerhttps://www.blogger.com/profile/10603765066800888538noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-7400820493450888372007-04-07T01:36:00.000-07:002007-04-07T01:36:00.000-07:00I think the real problem with pervasive partial ap...I think the real problem with pervasive partial application is that it disallows the possibility of variadic functions and the possibility functions with different type signatures sharing the same name, both of which are seriously useful features. So's pervasive partial application, of course: it's a difficult choice.<BR/><BR/>I too am a mathematician, albeit one in a different field to Michi: I don't have much problem reading Haskell's space-means-application convention (though I find its operator precedence very confusing, and as for do-notation, ugh!), but I'd be happier with parens for application, and space for composition, so f g h (x) means f(g(h(x))). But this is probably a minority opinion :-)Unknownhttps://www.blogger.com/profile/07136909835648629963noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-48334446614417854722007-02-20T15:58:00.000-08:002007-02-20T15:58:00.000-08:00> currying != partial applicationThank you for you...> currying != partial application<BR/><BR/>Thank you for your correction, but I think my point stands. My point is that the syntax for currying is unnecessarily burdensome. I *know* I can partially apply a function; I shouldn't have to write syntax that reminds me of that every time I write a function.<BR/><BR/>Anyway, I think (the more broad) partial application is more interesting than (the more specific) currying anyway. Currying suggests you must partially apply the arguments in order, whereas I think it's sometimes useful to apply them out of order, a la Python's "partial" function.<BR/><BR/>I feel like someone somewhere a long the line said, "currying is such a cool idea we should bake it into the syntax." I disagree. Tail recursion is really cool, but it's not baked into the syntax (fortunately).jjinuxhttps://www.blogger.com/profile/03270879497119114175noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-83533170017290917182007-02-20T15:51:00.000-08:002007-02-20T15:51:00.000-08:00> Maybe a new syntax front end: Liskell?My brain j...> Maybe a new syntax front end: Liskell?<BR/><BR/>My brain just exploded.jjinuxhttps://www.blogger.com/profile/03270879497119114175noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-76413922035368556022007-02-18T13:03:00.000-08:002007-02-18T13:03:00.000-08:00I wanted to learn Haskell a while ago, but I found...I wanted to learn Haskell a while ago, but I found that the syntax is unreadable and kind of gave up.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-11788780.post-47548765932971690452007-02-17T15:57:00.000-08:002007-02-17T15:57:00.000-08:00currying != partial applicationThey're opposite si...currying != partial application<BR/><BR/>They're opposite sides of the same coin, though. Currying is the property that a function of several arguments can be treated as a composition of several functions of one argument. Partial application is using that property to turn an N argument function into an N-1 argument function with the first argument bound.<BR/><BR/>So, if you have<BR/>> f :: a -> b -> c<BR/><BR/>Is that a function that takes an a and a b and returns a c? Or is it a function that takes an a and returns a function that takes a b and returns a c?<BR/><BR/>Then answer is Yes. Because it's both, depending on how you choose to use it. At least notionally, the first argument is consumed, a function returned, which consumes the second argument, which returns the result. But that's an as-if model, it certainly doesn't have to be implemented that way. <BR/><BR/>Still, if it really makes no sense to ever allow partial application, you could write<BR/><BR/>> g :: (a,b) -> c<BR/><BR/>That's a function that takes a tuple (pair) of an a and a b and returns a c.Steve Downeyhttps://www.blogger.com/profile/04633487339427038552noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-73904485391453619832007-02-17T10:58:00.000-08:002007-02-17T10:58:00.000-08:00Maybe a new syntax front end: Liskell?Maybe a new syntax front end: <A HREF="http://clemens.endorphin.org/liskell" REL="nofollow">Liskell</A>?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-11788780.post-75432527938975594632007-02-17T08:19:00.000-08:002007-02-17T08:19:00.000-08:00hi JJ,I agree with some...(.) and ($) are really r...hi JJ,<BR/><BR/>I agree with some...<BR/><BR/>(.) and ($) are really really annoying for human readers.<BR/><BR/>but also, the record issue was right on.<BR/><BR/>what we really need is a very, very friendly IDE. cheers.Imam Tashdid ul Alamhttps://www.blogger.com/profile/01603987396716404785noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-22097099044985822722007-02-16T18:01:00.000-08:002007-02-16T18:01:00.000-08:00It's interesting to note that Erlang isn't too far...It's interesting to note that Erlang isn't too far away from Haskell, and it follows many of my syntax suggestions. For instance: <BR/><BR/> * Function application is "lookup(Key, nil)".<BR/><BR/> * When you export a function, you show in the syntax how many arguments there are: "fac/1".<BR/><BR/> * Most function definitions don't look like curries, but you can create a function that behaves like a curry "Adder = fun(N) -> fun(X) -> X + N end end."<BR/><BR/>Remember, in general, I really like Haskell's semantics. I'm just looking for ways of offering those same semantics using syntax that is *intrinsically* more informative to someone who might not be familiar with all of the libraries involved.jjinuxhttps://www.blogger.com/profile/03270879497119114175noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-73447281479102515782007-02-16T17:55:00.000-08:002007-02-16T17:55:00.000-08:00> I think you've struck to the heart of a lot of s...> I think you've struck to the heart of a lot of serious problems with Haskell, and I'm glad someone had the guts to say this stuff.<BR/><BR/>Helpful comments. Thanks!jjinuxhttps://www.blogger.com/profile/03270879497119114175noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-58062911636720016812007-02-16T14:20:00.000-08:002007-02-16T14:20:00.000-08:00scruzia, jj: The reason I talked about getting the...scruzia, jj: The reason I talked about getting the compiler to understand what I'm writing is that I already am convinced that anyone decently up to speed reading my code will know what it means and does from just the amount of parenthesizing and syntactic help I put in there. Any more syntactic hints required will end up being in order to get it to go through the compiler as valid code, and Haskell has a very comfortable balance when it comes to that.<BR/><BR/>However; as I stated in my previous comment, and as might be blindingly obvious from the rest of my internetbased writings, I am writing this from the point of view of a mathematician who does programming and software design as well; not a programmer with possibly a slight interest in mathematics. This probably is a very important distinction, for all the subtlety it carries, but it is most definitely at the core of why I ended up in the Haskell community.michiexilehttps://www.blogger.com/profile/00008302080954798496noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-47742510937070001342007-02-16T12:45:00.000-08:002007-02-16T12:45:00.000-08:00I think you've struck to the heart of a lot of ser...I think you've struck to the heart of a lot of serious problems with Haskell, and I'm glad someone had the guts to say this stuff.<BR/><BR/>Background: I've done a lot of mathematics and theoretical computer science, and I really love haskell for its theoretical elegance and for what it's taught me about category theory.<BR/><BR/>BUT<BR/><BR/>I've also done a lot of software development, and I really find it hard to justify haskell for everyday work for reasons very similar to yours.<BR/><BR/>As I see it, the problem is a combination of these factors (forgive me if I generalise a little)<BR/> <BR/>- Haskell gives you a massive amount of flexibility in the syntax - in particular the flexibility to shoot yourself in the foot and make code overly dense, cryptic and unreadable. I share some of your bugbears, and will add the following: overuse of short, cryptic variable names, and overuse of custom operators which end up looking like line noise due to haskell's lexical parsing rules<BR/><BR/>- Haskell is mainly used by very smart people who value conciseness and theoretical elegance over practical readability, conventions and consistency<BR/><BR/>- Those developing haskell are often really interested in type systems and developing new awesomely clever extensions to Hindley-Milner (don't get me wrong, I find these things incredibly cool too, in a theoretical way - but but). The problem with this is that type system constraints have an excessive influence on the syntax, semantics and the programming conventions of the language - whereas to be truly useful for software development, it should be the other way round.<BR/><BR/>- Monads are Just Not Good Enough as an abstraction. They're very opaque and they don't compose well. You've hit the nail on the head with this - it's not that beginners are too stupid to grok monad transformers, it's that monad transformers aren't the right answer for structuring large programs. Most people are too in awe of their cleverness to really be blunt about this, but it is a big flaw that Haskell needs to overcome. No I don't have an answer myself, but more people should be looking for one.<BR/><BR/>Perhaps I've been excessively harsh there, but I say it out of love - I really want to see haskell do well!Matthhttps://www.blogger.com/profile/07759263441119052158noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-33556693325696272422007-02-16T11:40:00.000-08:002007-02-16T11:40:00.000-08:00I always hate when people say "I think language X ...I always hate when people say "I think language X needs these changes" and then list changes that basically take away everything that makes the language powerful.<BR/><BR/>There are thousands and thousands of languages out there, no reason to make every one of them hideous like C/C++/Java.<BR/><BR/>And the way currying works is wonderful. Haskell syntax is just beautiful. I can't imagine someone choosing yuck(x,y) over it.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-11788780.post-66631436392829349112007-02-16T11:21:00.000-08:002007-02-16T11:21:00.000-08:00If you don't like the syntax then don't use it. T...If you don't like the syntax then don't use it. There are *plenty* of languages that have the f(a,b) nonsense.<BR/><BR/>And it isn't clearer. If you come from a C/C++/Java background maybe, but if you come from e.g. smalltalk the f(a,b) syntax looks alien.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-11788780.post-77578983892562787982007-02-16T00:34:00.000-08:002007-02-16T00:34:00.000-08:00> Hi, JJ! I agree with you mostly about currying/s...> Hi, JJ! I agree with you mostly about currying/sectioning...I totally agree with JJ about points-free notation<BR/><BR/>It's nice to hear I'm not alone.<BR/><BR/>> THAT's a WRONG-HEADED way to look at it!!! You should be putting in the extra parentheses to get the HUMAN READER of your program to understand what you're writing. Write your code as if you're teaching another programmer how your code solves the given problem, instead of thinking of it as instructions directing the machine to do the operation that you have in mind.<BR/><BR/>I couldn't agree more! As a mathematician, you can afford to scrutinize some funny symbols. As a programmer, I'm faced with training new engineers how to maintain literally hundreds of thousands of lines of code. I care about readability even more than productivity, hence my post.<BR/><BR/>I always pretend I have someone looking over my shoulder reading when I'm programming. I think it helps.jjinuxhttps://www.blogger.com/profile/03270879497119114175noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-24738357326322608992007-02-15T22:49:00.000-08:002007-02-15T22:49:00.000-08:00Hi, JJ! I agree with you mostly about currying/s...Hi, JJ! I agree with you mostly about currying/sectioning, but I'd seek a middle ground were I to change the syntax. IMHO, the word "curry" is too heavyweight, and the total<BR/>absence of a clue (i.e., current Haskell syntax) is too lightweight. I kinda like the notion of using "_" or comma somehow.<BR/><BR/>Haskell's ($) was easy for me to get used to; I liked it right from the start.<BR/><BR/>I totally agree with JJ about points-free notation. I loathe it except in very very simple or very very uniform usages. IMHO the overuse of points-free notation in the Haskell community is one of the worst aspects of that community. I believe it in most cases to be a case of choosing to write code in a keystroke-saving way, instead of writing code to be understood. A mathematician's comment above underscores this unfortunate attitude:<BR/><I><BR/>"I very much like the fact that the Haskell syntax is so streamlined; that we don't need to sprinkle parens and other stuff, just to get the compiler to comprehend what I'm writing."<BR/></I><BR/><BR/>THAT's a WRONG-HEADED way to look at it!!! You should be putting in the extra parentheses to get the HUMAN READER of your program to understand what you're writing. Write your code as if you're teaching another programmer how your code solves the given problem, instead of thinking of it as instructions directing the machine to do the operation that you have in mind.<BR/><BR/>Ahem. To continue...<BR/><BR/><I>... those have some strong points over Java, but Java has one strength that kills each other: code reuse.<BR/></I><BR/><BR/>Can you say "Scala"?<BR/><BR/>Thanks to Cale for defending points-free -- nice explanation, but I still find it abhorrent and anti-helpful when people write much code that way.<BR/><BR/>I do think that operator precedence in Haskell is one of the harder things to get used to for beginners. Here's a feature I'd like to see in a Haskell IDE: visually parenthesize code (upon request, or by default for novices) by putting the background of the innermost parts in one shade, and holding the next outer parts together with a slightly lighter shade, fading out to match the background color at the outermost level. Do this in particular with the unfamiliar operators -- the ones that do not exist in the more popular languages.scruziahttps://www.blogger.com/profile/04753665681997405438noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-42970729518148156542007-02-15T18:52:00.000-08:002007-02-15T18:52:00.000-08:00> One reason you don't have to worry *too* much ab...> One reason you don't have to worry *too* much about under-applying functions, and ending up passing around functions when you think you're passing around other values is that the type checker is absolutely going to tell you exactly where you've gone wrong.<BR/><BR/>Yep.<BR/><BR/>> Check out shim, which is one of them. :)<BR/><BR/>Ah, interesting. I'm enough of a Vim nut to add Vim support, but not quite enough of a Haskell nut to find enough time among all my other projects ;) *sigh*<BR/><BR/>> Oh, by the way, sorry that I wasn't around when you popped up on IRC. I was taking a nap.<BR/><BR/>Thanks again for all your comments. You've been quite helpful!jjinuxhttps://www.blogger.com/profile/03270879497119114175noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-52075863683243799312007-02-15T18:45:00.000-08:002007-02-15T18:45:00.000-08:00Oh, by the way, sorry that I wasn't around when yo...Oh, by the way, sorry that I wasn't around when you popped up on IRC. I was taking a nap.Cale Gibbardhttps://www.blogger.com/profile/02239068589033148700noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-30180239420432598822007-02-15T18:44:00.000-08:002007-02-15T18:44:00.000-08:00Currying and partial application go hand in hand. ...Currying and partial application go hand in hand. It's a somewhat subtle distinction.<BR/><BR/>Currying is the process of treating functions of multiple parameters as if they only have one, and return a function which takes the rest.<BR/><BR/>Partial application is where you take something which is a curried function, and apply it to some, but not all of its parameters.<BR/><BR/>Regarding unwords, all that we'd lose is that we wouldn't know that spam was producing a list of strings. It would just have to produce something suitable for unwords to work with. (And yeah, notice that the reasoning I first provided was a lot more slow and methodical than the reasoning I really used at first, which is a faster way to look at it.)<BR/><BR/>One reason you don't have to worry *too* much about under-applying functions, and ending up passing around functions when you think you're passing around other values is that the type checker is absolutely going to tell you exactly where you've gone wrong. <BR/><BR/>While most of the IDEs for Haskell are not yet clever enough to point this out in realtime, putting red underlines beneath the type errors as you make them, there are a few which already are -- <A HREF="http://www.haskell.org/visualhaskell/index.html" REL="nofollow">Visual Haskell</A> being one of them. (Too bad it requires proprietary software and doesn't have really good screenshots on its website.) Don't worry, there are free software equivalents to this which are coming. The APIs which Visual Haskell uses to interoperate with GHC are free software, and there are some groups working on getting this capability into free IDEs.<BR/><BR/>Check out <A HREF="http://shim.haskellco.de/trac/shim" REL="nofollow">shim</A>, which is one of them. :)Cale Gibbardhttps://www.blogger.com/profile/02239068589033148700noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-43056448683378963442007-02-15T16:37:00.000-08:002007-02-15T16:37:00.000-08:00> F# has a little more sensible syntaxThat's so fu...> F# has a little more sensible syntax<BR/><BR/>That's so funny. When I defined a pipeline operator in my own code, I used "|>" too!jjinuxhttps://www.blogger.com/profile/03270879497119114175noreply@blogger.comtag:blogger.com,1999:blog-11788780.post-1568860964674496162007-02-15T16:14:00.000-08:002007-02-15T16:14:00.000-08:00The examples of '.' and '$' are spot on! F# has a...The examples of '.' and '$' are spot on! F# has a little more sensible syntaxfalconhttps://www.blogger.com/profile/12277230403055479892noreply@blogger.com