3 ms·
Trust me, it's better. Perl achieves conciseness by using global metavariables (e.g. $_, $/, etc.) which are silently updated by functions and that you have to
by ezyang 15y ago
Trust me, it's better. Perl achieves conciseness by using global metavariables (e.g. $_, $/, etc.) which are silently updated by functions and that you have to keep track of. Everything here is explicit; there are just lots of symbols...
- chromatic 15y agoCould you give examples of these silent updates in Perl? I'm by no means a Haskell expert, but one of the worst parts of learning Haskell (or reading arbitrary code) is that there's no special syntax for partial application. Certainly that's a benefit in many cases if you're familiar with the signatures of the functions you're using, but it's definitely not explicit.
- ezyang 15y agoConsider 'chomp', which to a first approximation removes trailing whitespace from a variable. If you don't pass it any variables, it modifies the $_ variable. Better hope you know what's in there. Furthermore, it's behavior depends on what $/ is set to; if you set $/ to something else, it will do something different. Run 'perldoc perlvar' for more examples. Lack of special syntax for partial application can be confusing for a lot of beginners; it certainly is very confusing if you're implementing, say, the continuation monad. But I think a lot of people overestimate the extent to which partial application appears in normal code: usually you fill up all the arguments except the last one, which is shuttled in via =<< or something similar. You don't have to think too hard about it, because the typechecker will make sure you've put all the functions together properly.
- tikhonj 15y agoPartial application also tends to be very useful for writing functions in a clear "point-free" style--that is, without naming arguments; it is also very nice for higher-order functions like map and filter.
- tikhonj 15y agoHow about this: map{ tr/a-z/A-Z/; print $_ }@array; I don't remember the exact syntax, but the tr acts on $_ by default, and $_ starts out as each element of the array.
- draegtun 15y agoIn map, $_ is a localised reference. Thus it doesn't clobber $_ my @array = qw/one two three/; $_ = "Hello"; say; map { tr/a-z/A-Z/ } @array; say; prints.... Hello Hello However remember it's a reference so using tr// will update @array... say "@array"; # => ONE TWO THREE
- tel 15y agoIt's because you think of functions differently in Haskell. They're not running processes which are delayed by partial application but instead partially constrained unifications. Which is sort of worse sounding, but it becomes quite natural once you start writing using types. I think of it like using legos. makeLegoman :: Legs -> Torso -> Head -> Legoman makeLegoman some_legs :: Torso -> Head -> Legoman makeLegoman some_legs some_torso some_head :: Legoman
- tikhonj 15y agoHeh, I really like the Lego man example. I'm going to have to use it in the future.
- amalcon 15y agoRegex capture is the most obvious one. The $N variables are updated silently. You just don't think about it because it's so central to Perl. There are also many things that update $_.
- o1iver 15y agoThere is no special syntax for partial application because in Haskell partial application is always possible. You can call the function foo :: a -> b -> c like this bar = foo a or like this: bar = foo a b. In the first case bar will be a partially applied function of type bar :: b -> c and in the second case it will simply be a value of type c. Actually, as far as I know, this is actually what happens in the background. I mean that calling bar = foo a b actually gets converted to bar = (foo a) b.
- chromatic 15y agoThere is no special syntax for partial application because in Haskell partial application is always possible. I am aware of this. This is the source of some of my frustration reading Haskell code. I know that you can think of functions as single-arity first-class entities, but I've never been a mathematician and I've never thought that way. I don't have enough experience maintaining large Haskell programs over a long period of time to know, but I suspect that this layering approach might encourage the kind of convolution you occasionally find in CL or Smalltalk programs where it's easy to build a teetering tower of the wrong abstractions. Perhaps there's something different about Haskell that encourages a more careful code curation, but I don't know. Alternately, perhaps it's just a flaw in the way I think about Haskell that I want a visual distinction between partial application and calling a function.