|
View:
New views
6 Messages
—
Rating Filter:
Alert me
|
|
|
Point free (pointless) programming in ruby? (fwd)Here's a post I sent to the ruby mailing list about doing pointfree /
concatenative like things in Ruby. Perhaps some of the Denizens of this list might like to apply their wondrously creative minds to the exercise. John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@... New Zealand ---------- Forwarded message ---------- Date: Wed, 14 Jan 2009 12:12:00 +1300 (NZDT) From: John Carter <john.carter@...> To: ruby-talk ML <ruby-talk@...> Subject: Point free (pointless) programming in ruby? I'm very fond of the notion of Concatenative Languages such as Joy, Factor... http://en.wikipedia.org/wiki/Joy_(programming_language) http://www.latrobe.edu.au/philosophy/phimvt/joy/jp-joyjoy.html http://factorcode.org/ There is a supreme simplicity about them. So while reading what the current state of them is, I stumbled across the notion of Point free (sometimes called Pointless) programming. The idea of sequences of function compositions that elide the arguments that they will be applied to. http://www.haskell.org/haskellwiki/Pointfree One can easily define a sequence of methods in Ruby... fun_seq = [:a, :b, :c] as a sequence of symbols. Which one could apply to an arbitrary argument.. irb > f = [:to_s, :succ] => [:to_s, :succ] > f.inject(4,:send) => "5" Oooh! Looky! That's sneaky of me! symbol_sequence.inject(arg,:send) [:a, :b, :c].inject(arg,:send) that's equivalent to arg.a.b.c Not quite function composition. Cute, but let's try... irb > def a(a) > p ["a",a] > a+"a" > end => nil > def b(b) > p ["b",b] > b+"b" > end => nil > def c(c) > p ["c",c] > c+"c" > end => nil > f=[:a,:b,:c] => [:a, :b, :c] > f.inject("foo"){|memo,obj|send(obj,memo)} ["a", "foo"] ["b", "fooa"] ["c", "fooab"] => "fooabc" [:a, :b, :c].inject(arg){|memo,obj|send(obj,memo)} is equivalent to c(b(a(arg))) > c(b(a("bah"))) ["a", "bah"] ["b", "baha"] ["c", "bahab"] => "bahabc" Or how about working with lambda's or Proc objects... > a1 = lambda {|x| x+"a"} => #<Proc:0xb7d9f744@(irb):41> > b1 = lambda {|x| x+"b"} => #<Proc:0xb7e0feb8@(irb):42> > c1 = lambda {|x| x+"c"} => #<Proc:0xb7dfa5e0@(irb):43> > [a1, b1, c1] => [#<Proc:0xb7d9f744@(irb):41>, #<Proc:0xb7e0feb8@(irb):42>, #<Proc:0xb7dfa5e0@(irb):43>] > [a1, b1, c1].inject("foo"){|memo,proc| proc.call(memo)} => "fooabc" Anyhoo! Clearly in principle one can do Pointfree programming Ruby. Questions for the Group: 1) Is there a neater way of expressing a sequence of function compositions in Ruby? 2) Which Ruby Pointfree sequences are actually useful? John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@... New Zealand |
|
|
Re: Point free (pointless) programming in ruby? (fwd)On Jan 13, 2009, at 6:15 PM, John Carter wrote: > 1) Is there a neater way of expressing a sequence of function > compositions in Ruby? Evaluation of a concatenative language is just a fold of 'apply' over your list of functions with the empty list as the initial element. For example, in Scheme: (define (ceval fs) (fold apply '() fs)) Your Ruby version is essentially the same thing. > 2) Which Ruby Pointfree sequences are actually useful? All you can really do is implement a concatenative language inside Ruby complete with its own standard library. This is probably not so useful. Languages like ML and Haskell work better because they have curried functions. There even exists a tool for automatically translating pointful Haskell functions to point-free Haskell functions, although the results are often less than clear: \x y z -> y * z - x == flip (flip . ((-) .) . (*)) You may want to look at the following: http://www.haskell.org/haskellwiki/Pointfree Keep in mind that all existing concatenative languages make heavy use of stacks. Related languages like FP and FL make heavy use of lists. Trying to do pointfree programming in languages that don't do such things (Ruby, Python, Haskell, Scheme, etc) is going to be quite painful. For example, here's the Haskell example above in Joy: * swap - And in a concatenative FP-style language: - [hd, * tl] - John |
|
|
Re: Point free (pointless) programming in ruby? (fwd)On Tue, 13 Jan 2009, John Nowak wrote:
> Languages like ML and Haskell work better because they have curried > functions. I wonder if Curried Functions have the same effect as Curried Eggs have on the digestive system? Actually Currying works quite well in Ruby... two_arg = lambda{|a,b| somefunc(a,b)} b="Some concrete value" one_arg = lambda{|a| two_arg.call(a,b)} one_arg.call("Single parameter") is equivalent to someFunc( "Single Parameter", "Some concrete value") > Keep in mind that all existing concatenative languages make heavy use > of stacks. Related languages like FP and FL make heavy use of lists. > Trying to do pointfree programming in languages that don't do such > things (Ruby, Python, Haskell, Scheme, etc) is going to be quite > painful. For example, here's the Haskell example above in Joy: Well, actually Ruby has Array's that behave (or can be made to behave) in almost all respects like lists. The obj.a.b.c.d.e form would be effectively identical to the concantenative stack to stack functions if obj was an Array and each method a, b, c, d, e was a non-destructive Array method returning an Array. Well, actually Rubies Duck Typing extends that in interesting ways. See the Ruby Enumerable mixin for an example. ie. Ruby is a superset of concatenative languages. ie. If one restricts ones activities to a suitable concatenative subset, the same interesting properties emerge. The question then remains... What interesting idioms could one evolve by playing in that subset. John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@... New Zealand |
|
|
Re: Point free (pointless) programming in ruby? (fwd)On Jan 15, 2009, at 5:37 PM, John Carter wrote: > On Tue, 13 Jan 2009, John Nowak wrote: > >> Languages like ML and Haskell work better because they have curried >> functions. > > Actually Currying works quite well in Ruby... > > two_arg = lambda{|a,b| somefunc(a,b)} > > b="Some concrete value" > one_arg = lambda{|a| two_arg.call(a,b)} That is not currying. Unfortunately, this is something of a common misunderstanding. A curried function is one that emulates taking more than one argument by using many functions that take a single argument. For example, here's a function in Haskell that adds three numbers: foo = \x y z -> x + y + z And here's *the exact same function* with a different name: bar = \x -> (\y -> (\z -> x + y + z)) When you write the former, you're really doing the later. Both can be called identically as they're exactly the same thing: foo (1, 2, 3) -- 6 bar (1, 2, 3) -- 6 Because 'foo' and 'bar' are curried, we can do this to mean the *exact same thing* once again; this is called partial application: ((foo 1) 2) 3 -- 6 ((bar 1) 2) 3 -- 6 Additionally, Haskell offers a function for currying a function: curry (\(x, y) -> x + y) == \x y -> x + y And uncurrying: uncurry (\x y -> x + y) == \(x, y) -> x + y Now, you *can* write a curried function in Ruby like so: baz = lambda{|a| lambda{|b| lambda{|c| a + b + c}}} And call it as such: baz.call(1).call(2).call(3) # 6 Unfortunately, it's quite painful. I'm not sure where the confusion with respect to "curry" started. Factor is an example of a language that unfortunately misuses the term. >> Keep in mind that all existing concatenative languages make heavy use >> of stacks. Related languages like FP and FL make heavy use of lists. >> Trying to do pointfree programming in languages that don't do such >> things (Ruby, Python, Haskell, Scheme, etc) is going to be quite >> painful. For example, here's the Haskell example above in Joy: > > Well, actually Ruby has Array's that behave (or can be made to behave) > in almost all respects like lists. Yes, you could write all new functions that operate on stacks instead of using normal parameters. Ruby performance being what it is though, I can't imagine this being useful for much of anything. Languages like Factor do analysis to eliminate constant reading from and writing to a stack which improves performance dramatically. Having to update an array's contents, make bounds checks, update an array's length, and so on just to add two numbers doesn't sound like fun. > ie. Ruby is a superset of concatenative languages. > ie. If one restricts ones activities to a suitable concatenative > subset, the same interesting properties emerge. Yes, if you rewrite every function to work on stacks and use none of Ruby's features, you will have a very poor concatenative language with awful syntax. Of course, one can implement Ruby's features in a concatenative language too. It's therefore a bit silly to claim one is a superset of the other. - John |
|
|
Re: Point free (pointless) programming in ruby? (fwd)On Thu, 15 Jan 2009, John Nowak wrote:
> That is not currying. Unfortunately, this is something of a common > misunderstanding. You are right, sorry. > Now, you *can* write a curried function in Ruby like so: > > baz = lambda{|a| lambda{|b| lambda{|c| a + b + c}}} > > And call it as such: > > baz.call(1).call(2).call(3) # 6 > > Unfortunately, it's quite painful. Try an alternate syntax then... irb irb(main):001:0> baz = lambda{|a| lambda{|b| lambda{|c| a + b + c}}} => #<Proc:0xb7d94ab0@(irb):1> irb(main):002:0> baz[1] => #<Proc:0xb7d94ba0@(irb):1> irb(main):003:0> baz[1][2] => #<Proc:0xb7d94c40@(irb):1> irb(main):004:0> baz[1][2][3] => 6 > It's therefore a bit silly to claim one is a superset of the other. Perhaps a better way of putting it would given the very flexible multi-paradigm nature of Ruby, one can borrow the "Pointfree" paradigm as well. Will it be useful? Well, I suspect it might be. I haven't seen anything yet that has given me the urge to rip Ruby out as my main day to day programming workhorse. However there are parts of the concatenative languages that make feel "ooh that has so much promise... but not quite something I can convince my boss about". Ruby doesn't quite comfortably replace the *sh languages yet. One area that has been a bit hard to express is the *sh '|' pipelines. I'm playing with the idea of pointfree in ruby as a nice paradigm to do pipelined oneliners and more. John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@... New Zealand |
|
|
Re: Point free (pointless) programming in ruby? (fwd)On Jan 15, 2009, at 8:49 PM, John Carter wrote: > I haven't seen anything yet that has given me the urge to rip Ruby out > as my main day to day programming workhorse. >> x = 0 => 0 >> x => 0 >> lambda{|x| 0}.call(5) => 0 >> x => 5 That gave me the urge to do something alright. Yes, I realize it has been fixed. Unfortunately it took 12 years, which can only mean that those involved have no clue what they're doing. But now I'm just being rude... - John |
| Free embeddable forum powered by Nabble | Forum Help |