News for hackers. Stuff that matters.
Re:PHP in a Tweet by whalesalad on Tuesday October 08, 2013 @03:36PM (#6517295)
I enjoy PHP like I enjoy going home to see my family for the holidays. It's fun for a bit, the nostalgia makes me feel warm and fuzzy, and the familiarity of everything is very comforting. You quickly realize though that the grass really is a lot greener on the other side. You remember why you moved out of your parent's place and went out on your own.

It's hilarious looking at how cryptic these one-liners are, particularly when I consider that with languages like Ruby and Python you can do a LOT with a tiny little line if code.

As a side-note, one of my favorites is summing an array in Ruby:

  x = [1, 2, 3, 4, 5]
  x.inject &:+
  => 15
Re:PHP in a Tweet by sevenproxies on Tuesday October 08, 2013 @03:57PM (#6517420)
In PHP

   array_sum([1, 2, 3, 4, 5]);
Re:PHP in a Tweet by cheald on Tuesday October 08, 2013 @06:18PM (#6518218)
The GP's point is that Ruby doesn't require a built-in method that specifically sums an array to still get a clean, terse operation. You can use #inject to apply an arbitrary operation to (operator, last result, current element) and arrive at a result.

For example, given a list of numbers, you can generate a bitwise OR mask easily:

    [1,2,3,4,5].inject(:|)
What this does is iterate over the list and apply ($last_result | $current_element) and return the result, which is passed on as $last_result to the next iteration. $last_result is 0 by default. This is equivalent to (as of PHP 5.4):

    array_reduce([1,2,3,4,5], function($v, $e) { return $v | $e; }, 0);
Or prior to PHP 5.3:

    function or_mask($v, $e) { return $v | $e; }
    array_reduce(array(1,2,3,4,5), "or_mask", 0);
It's doable in both languages, but Ruby's functional language lineage and its object-oriented nature results in an exceptionally clean approach.
Re:PHP in a Tweet by TeMPOraL on Tuesday October 08, 2013 @06:41PM (#6518324)
Prior to PHP 5.3 this could work as well:

    array_reduce(array(1,2,3,4,5), create_function('$v, $e', 'return $v | $e;'), 0);
Re:PHP in a Tweet by cheald on Tuesday October 08, 2013 @06:46PM (#6518347)
I'm really glad that 5.3 got proper anonymous functions. Specifying function bodies as strings to be eval'd makes me twitch.
Re:PHP in a Tweet by tel on Tuesday October 08, 2013 @04:27PM (#6517612)
In case this was a serious entry... which I honestly can't tell.

The problem with array_sum is not that it's too long but instead that it's combined two rather specific bits of functionality into a fixed (if common) form, while the Ruby code separates the ideas of "folding" and "addition" allowing for many orthogonal creations.

To pick another favorite, in Haskell you could write

    Foldable.foldl1 (+)
which sums any foldable thing—anything which has elements which can be combined together one-by-one. So it'll apply to Trees or Sets or Dictionaries (well, Maps) just as easily while also allowing things like (+) to be replaced by other binary operators.
Re:PHP in a Tweet by Scriptor on Tuesday October 08, 2013 @05:07PM (#6517863)
PHP does have array_reduce, however operators like '+' can't be used as callables so you'd have to make your own wrapper functions.

Edit: Screw it, haven't self promoted on a while. In Pharen (https://github.com/scriptor/pharen), which compiles to PHP, you could do:

    (reduce (+) 0 [1 2 3 4 5])
Re:PHP in a Tweet by tel on Tuesday October 08, 2013 @06:56PM (#6518395)
That's really cool, but the syntax is strange to me. How do you distinguish between operator sectioning (+) and a side-effecting function call (f)?
Re:PHP in a Tweet by Scriptor on Tuesday October 08, 2013 @07:15PM (#6518491)
It works (superficially) similarly to how Haskell does things and treats (+) as a partial function call by recognizing that + isn't getting at least 2 arguments. You could also do stuff like:

    ((+ 1) 2) ; => 3

    (map (* 2) [1 2 3]) ; => [2 4 6]
If a function f takes any arguments and Pharen knows this, it'll convert (f) into a partial function call as well. Unfortunately I haven't figured out a way to check if a function has any side effects. Otherwise in this case at least operators are treated like functions.
Re:PHP in a Tweet by tel on Tuesday October 08, 2013 @07:47PM (#6518621)
So it's tracking the arity of functions and turning anything which has been applied to fewer than ARITY arguments to a partial application?

I suppose that comes at the cost of (+ 1 2 3 4)?

Re:PHP in a Tweet by Scriptor on Wednesday October 09, 2013 @01:49AM (#6519622)
It does track the arity of functions, but remember that this happens at compile time. Regular addition in Pharen is still just regular addition in PHP:

    (def a (+ 1 2 3 4)) ; => $a = (1 + 2 + 3 + 4);
Of course, there are situations where partial application won't always happen because the compiler is unable to detect it:

    (fn add (x y)
      (+ x y))

    (map #add [1 2 3])
Pharen won't be able to realize that `add` here is being partially applied inside `map`. It's not smart enough for that yet. If you try to run this you'll end up with 'Missing argument 2' and 'Undefined variable: y' all over the place.

However, I'm not putting a whole lot of emphasis on partials. They're there as a convenience, but they're not really a core part of the language.

But yes, back to the original point, all the tracking is done at compile time so that for addition with two or more arguments the resulting PHP will look like regular addition in PHP.

Re:PHP in a Tweet by tel on Wednesday October 09, 2013 @09:16AM (#6521022)
Gotcha, very interesting!
Re:PHP in a Tweet by knome on Tuesday October 08, 2013 @10:21PM (#6519090)
Surprisingly, not really.

    {-# OPTIONS -fglasgow-exts #-}
    
    class BuildList a r  | r-> a where
      build' :: [a] -> a -> r
    
    instance BuildList a [a] where
      build' l x = reverse$ x:l
    
    instance BuildList a r => BuildList a (a->r) where
      build' l x y = build'(x:l) y
    
    varargs x = build' [] x
    
    main = print $ ( sum $ varargs 1 2 3 4 5 6 100)


    $ ./Test
    121

    
http://okmij.org/ftp/Haskell/vararg-fn.lhs
Re:PHP in a Tweet by tel on Wednesday October 09, 2013 @09:17AM (#6521024)
I love that example, but it does depend upon some pretty arcane features in Haskell's type inference engine.
Re:PHP in a Tweet by aaronem on Tuesday October 08, 2013 @09:54PM (#6519018)
Why would it?
Re:PHP in a Tweet by tel on Wednesday October 09, 2013 @09:19AM (#6521036)
My hypothesis was that the compiler was tracking the arities of each function in order to open up opportunities for partial application. That means there's some ambiguity when you write something like (+ 1) which, in Scheme is a complete application equal to 1 but may also be interpreted as a partial application equal to (lambda (x) (+ 1 x)).

There are many ways to mitigate that ambiguity statically and dynamically, but I feel there's always going to be a tradeoff between favoring partial application, favoring variadic functions, and the complexity/sophistication of your static checking or runtime environment.

I just made a stab at where the solution might lie in that design space. Turns out I was wrong.

Re:PHP in a Tweet by afrdofdwnvtes on Tuesday October 08, 2013 @05:19PM (#6517924)
Well how about this then.

    foreach(array(1,2,3,4,5) as $x) $i=$i+$x; echo $i;
Re:PHP in a Tweet by tel on Tuesday October 08, 2013 @07:00PM (#6518416)
The array_reduce answers get closer to what I was looking for. This might be a "one line" answer, but it requires two special forms, assignment, sequencing operators (;), and two fresh variables.
Re:PHP in a Tweet by paul_f on Tuesday October 08, 2013 @09:11PM (#6518918)
This works, is fast enough and readable. Perfectly fine solution to me.
Re:PHP in a Tweet by 7Figures2Commas on Tuesday October 08, 2013 @05:29PM (#6517970)
1. Separate folding and addition.

2. ?

3. Profit.

Re:PHP in a Tweet by tel on Tuesday October 08, 2013 @06:59PM (#6518406)
Orthogonality and composability dramatically increase abstraction, code reuse, testability, and likelihood of writing correct code, both for library maintainers and library users.

Step 2 is actually extremely well known.

Re:PHP in a Tweet by DorianMarie on Tuesday October 08, 2013 @03:59PM (#6517438)
array_sum_of_1_2_3_4_5();

(Added in PHP 6)

Re:PHP in a Tweet by krapp on Tuesday October 08, 2013 @06:21PM (#6518228)
the funny thing is, with proper abuse of __call you can almost get that to work: https://gist.github.com/kennethrapp/328b6bd1bda8a8f94092
Re:PHP in a Tweet by aaronem on Tuesday October 08, 2013 @10:03PM (#6519036)
That's not funny. Horrifying, maybe, but not funny.

Edit: Strike 'maybe'. I looked at it again and it's definitely horrifying. I saved it anyway, though; Halloween's only a few weeks off, and I think I shall print it out and stick it on the wall of my cube next to the PHP hammer and the "periodic" table of Perl 6 operators.

Re:PHP in a Tweet by agumonkey on Wednesday October 09, 2013 @07:09AM (#6520519)
kudos. almost as cool as the cpp template hack to compute area based on part of the source code 'ascii art' size. (which I can't find anymore. googlefu--)
Re:PHP in a Tweet by x3ro on Tuesday October 08, 2013 @04:21PM (#6517569)
Made me laugh :)
Re:PHP in a Tweet by TylerE on Tuesday October 08, 2013 @04:36PM (#6517672)

    irb(main):001:0> x = [1,2,3,4,5]
    => [1, 2, 3, 4, 5]
    irb(main):002:0> x.inject &:*
    => 120
Re:PHP in a Tweet by dubcanada on Tuesday October 08, 2013 @06:12PM (#6518177)
These "one-liners" are cryptic because they are complex, it's a what can you do in the smallest form possible. It doesn't require code readability. Obviously you wouldn't use a 120 character dependency injector. That's just silly. But you can make one in 120 characters.
Re:PHP in a Tweet by tel on Tuesday October 08, 2013 @07:03PM (#6518433)
I disagree. I think they're simpler because they're built of smaller numbers of orthogonal concepts. I think code like this is certainly more dense, but I find the consequence of that density is that I spend less time pattern matching and skipping over "things that look like common idioms" and more time thinking about how there large, powerful abstractions wire together to achieve the intended end.
Re:PHP in a Tweet by dugmartin on Tuesday October 08, 2013 @03:57PM (#6517419)
Or one true line in APL:

    +/ 1 2 3 4 5
Re:PHP in a Tweet by lkey on Tuesday October 08, 2013 @08:30PM (#6518783)
Since we are golfing...

+/⍳5

Re:PHP in a Tweet by draegtun on Wednesday October 09, 2013 @11:44AM (#6521967)
Here it is in Perl6:

  [+] ^6
Actually cheated slightly because ^6 creates list from 0..5 :)

So correct match would be...

  [+] 1..5
Here's how you would do it in Io:

  list(1, 2, 3, 4, 5) reduce(+)
In Rebol there isn't a functional fold/reduce built in. So one way to do the one-liner would be:

  x: [1 2 3 4 5] forskip x 2 [insert x '+] x: do next x
Above changes x to 15. Alternatively approach which doesn't clobber x:

  x: [1 2 3 4 5] y: [] forall x [repend y [x/1 '+]] take/last y do y
I'm sure someone with more Rebol chops can see other (better!) ways of doing this :)
Re:PHP in a Tweet by shaunxcode on Tuesday October 08, 2013 @03:59PM (#6517432)
Re:PHP in a Tweet by epidemian on Tuesday October 08, 2013 @10:15PM (#6519070)
Yeah, but remember to pass the 0 to it; otherwise the sum of an empty array would be nil:

  x.inject(0, &:+)
That's one of the disadvantages of not having a powerful type system to infer what's the "zero" of some type.

Still, the Ruby code is pretty readable and a good example of orthogonal concepts that compose well. E.g., getting the product of the numbers instead: x.inject(1, &:*). Or the least common multiple: x.inject(&:lcm).

Re:PHP in a Tweet by ramigb on Tuesday October 08, 2013 @07:35PM (#6518570)
[1,2,3,4,5].reduce(:+) Or in case of a range ... (1...6).reduce(:+)

I'm sorry i couldn't fight the urge to FIFY :( ...

Re:PHP in a Tweet by aaronem on Tuesday October 08, 2013 @09:58PM (#6519022)
It's a good fix and no bad thing to point out, and I'm not just saying that because I was about to point out the same thing before I noticed you'd beat me to it.