ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: "rosenfeld (Rodrigo Rosenfeld Rosas)" <rr.rosas@gmail.com>
To: ruby-core@ruby-lang.org
Subject: [ruby-core:49197] [ruby-trunk - Feature #6284] Add composition for procs
Date: Sat, 10 Nov 2012 21:33:09 +0900	[thread overview]
Message-ID: <redmine.journal-32748.20121110213305@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-6284.20120412152125@ruby-lang.org


Issue #6284 has been updated by rosenfeld (Rodrigo Rosenfeld Rosas).


In Math multiplication is always associative, even for matrix. I.e: (A*B)*C == A*(B*C). If we use * for ∘ (composition) it resembles multiplication. Function composition is analog to matrix multiplication which are commonly used for transformation compositions as well. In fact, function composition is also associative.

So, when representing h = f ∘ g as h = f * g it makes sense to me (although Math preferring a different symbol for multiplication and composition is a good indication that we should consider this as well for Ruby - more on that later on). But Math representation is procedural, not object oriented. If we try to mix both approaches to fit Ruby philosophy this could lead to great confusion.

Ruby can be also used for procedural programming:

sqrt = ->(n){ Math.sqrt n } # Although I agree that (n)->{} would read more natural to me, just like in CoffeeScript
square_sum = ->(a, b) { a*a + b*b }
hypotenuse = sqrt * square_sum
5 == hypotenuse.call 3, 4 # equivalent to: sqrt.call square_sum.call 3, 4

This makes total sense to me using procedural notation. I'm not sure how would someone use this using some OO notation instead...

Now with regards to composition notation, I think a different notation could help those reading some code and trying to understand it. Suppose this method:

def bad_name(bad_argument_name, b)
  bad_argument_name * b # or bad_argument_name << b
end

You can't know beforehand if bad_argument_name is an array, a number or a proc/lambda. If we read this instead:

def bad_name(bad_argument_name, b)
  bad_argument_name <- b
end

we would then have a clear indication that bad_argument_name is probably a proc/lambda. I know the same argument could be used to differentiate << between strings and arrays among other cases. But I think that function composition is conceptually much different from those other operations (concatenation, multiplication) than concatenation (<<) is for strings and arrays. In both cases we are concatenating but concatenation means different things for strings and arrays in non surprising ways.

But then using this arrow notation I would expect that (a <- b) would mean "a before b" (b(a(...))) while (a ∘ b) means "a after b" (a(b(...))).

I find it a bit awful to use "hypotenuse = square_sum <- sqrt", although it is the way OO usually work ([4, 5].square_num.sqrt - pseudo-code of course). But we would not be using "[4, 5].hypotenuse", but "hypotenuse.call 4, 5", right? So, since we're using procedural notation for procs/lambdas we should be thinking of procedural programming when deciding which operator to use.

I would really prefer to have lambda syntax as "double = <-{|n| n * 2}" and function composition as "hypotenuse = sqrt -> square_sum" (sqrt after square_sum). But since I don't believe the lambda syntax won't ever change, let's try to see this over a different perspective.

Instead of reading (a <- b) as "a before b", I'll try to think of it as being "b applied to a" (a(b(...))). This also make sense to me so I can easily get used to this. It would work the same way as "*" but there would be a clear indication that this refers to function composition rather than some generic multiplication algorithm.

Having said that, I'd like to confirm that I'm ok with either * or <- and I'd really like to have function composition as part of Ruby.
----------------------------------------
Feature #6284: Add composition for procs
https://bugs.ruby-lang.org/issues/6284#change-32748

Author: pabloh (Pablo Herrero)
Status: Feedback
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: 
Target version: 2.0.0


=begin
It would be nice to be able to compose procs like functions in functional programming languages:

    to_camel = :capitalize.to_proc
    add_header = ->val {"Title: " + val}

    format_as_title = add_header << to_camel << :strip

instead of:

    format_as_title = lambda {|val| "Title: " + val.strip.capitalize }


It's pretty easy to implement in pure ruby:

  class Proc
    def << block
      proc { |*args| self.call( block.to_proc.call(*args) ) }
    end
  end
=end


-- 
http://bugs.ruby-lang.org/

  parent reply	other threads:[~2012-11-10 12:31 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-12  6:21 [ruby-core:44303] [ruby-trunk - Feature #6284][Open] Add composition for procs pabloh (Pablo Herrero)
2012-04-12 14:26 ` [ruby-core:44308] [ruby-trunk - Feature #6284] " trans (Thomas Sawyer)
2012-04-12 14:28 ` [ruby-core:44309] " trans (Thomas Sawyer)
2012-04-12 17:02 ` [ruby-core:44313] " pabloh (Pablo Herrero)
2012-04-12 21:26 ` [ruby-core:44319] " alexeymuranov (Alexey Muranov)
2012-04-12 21:39   ` [ruby-core:44320] " Adam Prescott
2012-04-12 22:53 ` [ruby-core:44321] [ruby-trunk - Feature #6284][Assigned] " mame (Yusuke Endoh)
2012-04-12 23:59 ` [ruby-core:44323] [ruby-trunk - Feature #6284] " pabloh (Pablo Herrero)
2012-04-13  5:56 ` [ruby-core:44327] " alexeymuranov (Alexey Muranov)
2012-04-15  8:10 ` [ruby-core:44365] " trans (Thomas Sawyer)
2012-04-16  2:59 ` [ruby-core:44373] " pabloh (Pablo Herrero)
2012-10-27  1:44 ` [ruby-core:48422] [ruby-trunk - Feature #6284][Feedback] " matz (Yukihiro Matsumoto)
2012-11-09  9:56 ` [ruby-core:49156] [ruby-trunk - Feature #6284] " jballanc (Joshua Ballanco)
2012-11-09 11:10 ` [ruby-core:49159] " rosenfeld (Rodrigo Rosenfeld Rosas)
2012-11-09 11:23 ` [ruby-core:49161] " rohitarondekar (Rohit Arondekar)
2012-11-09 16:25 ` [ruby-core:49169] " alexeymuranov (Alexey Muranov)
2012-11-09 17:42 ` [ruby-core:49171] " marcandre (Marc-Andre Lafortune)
2012-11-10  3:06 ` [ruby-core:49182] " duerst (Martin Dürst)
2012-11-10  4:00   ` [ruby-core:49184] " Matthew Kerwin
2012-11-10  9:23 ` [ruby-core:49190] " alexeymuranov (Alexey Muranov)
2012-11-10 12:33 ` rosenfeld (Rodrigo Rosenfeld Rosas) [this message]
2012-11-24  1:31 ` [ruby-core:49947] " mame (Yusuke Endoh)
2012-12-01 19:54 ` [ruby-core:50461] " rits (First Last)
2012-12-05  3:13 ` [ruby-core:50563] " boris_stitnicky (Boris Stitnicky)
2012-12-05 10:47 ` [ruby-core:50568] " rosenfeld (Rodrigo Rosenfeld Rosas)
2012-12-05 11:23 ` [ruby-core:50569] " alexeymuranov (Alexey Muranov)
2015-06-14 16:55 ` [ruby-core:69586] [Ruby trunk " mudge
2015-06-23 14:47 ` [ruby-core:69712] " mudge
2015-06-29  8:39 ` [ruby-core:69768] " mudge
2015-06-29 21:32 ` [ruby-core:69777] " pablodherrero
2015-06-30  8:21 ` [ruby-core:69812] " duerst
2015-06-30  8:35 ` [ruby-core:69813] " eregontp
2015-06-30 11:37 ` [ruby-core:69816] " pablodherrero
2015-06-30 12:39 ` [ruby-core:69817] " mudge
2015-07-01 15:52 ` [ruby-core:69833] " tom
2015-08-07  7:21 ` [ruby-core:70264] " systho
2015-12-30 11:18 ` [ruby-core:72616] " mudge
2015-12-30 12:28 ` [ruby-core:72618] " mudge
2016-10-09 14:30 ` [ruby-core:77534] [Ruby trunk Feature#6284] " bigbadmath
2016-10-11 20:18 ` [ruby-core:77595] " mudge
2016-10-12  8:28 ` [ruby-core:77597] " mudge
2016-10-12  9:46 ` [ruby-core:77599] " duerst
2017-01-22 18:50 ` [ruby-core:79219] " t.hirsch
2017-03-13  8:13 ` [ruby-core:80110] " matz
2017-04-28 19:47 ` [ruby-core:80931] " ritchie
2017-08-31  6:26 ` [ruby-core:82555] " ozaki
2018-01-29  7:49 ` [ruby-core:85213] " zverok.offline
2018-04-20 18:34 ` [ruby-core:86632] " keystonelemur
2018-04-30 18:51 ` [ruby-core:86780] " keystonelemur
2018-05-17  5:56 ` [ruby-core:87100] [Ruby trunk Feature#6284][Open] " matz
2018-07-30  8:13 ` [ruby-core:88188] [Ruby trunk Feature#6284] " melentievm
2018-08-08  5:41 ` [ruby-core:88339] " ko1
2018-08-08 18:37 ` [ruby-core:88356] " shannonskipper
2018-08-10 19:58 ` [ruby-core:88442] " shannonskipper
2018-11-12 12:43 ` [ruby-core:89775] " nobu
2018-11-14 17:33 ` [ruby-core:89796] " pablodherrero
2018-11-15  2:22 ` [ruby-core:89801] " nobu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-32748.20121110213305@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).