ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:94432] [Ruby master Feature#16113] Partial application
       [not found] <redmine.issue-16113.20190819100716@ruby-lang.org>
@ 2019-08-19 10:07 ` zverok.offline
  2019-08-19 11:11 ` [ruby-core:94433] " shevegen
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 6+ messages in thread
From: zverok.offline @ 2019-08-19 10:07 UTC (permalink / raw)
  To: ruby-core

Issue #16113 has been reported by zverok (Victor Shepelev).

----------------------------------------
Feature #16113: Partial application
https://bugs.ruby-lang.org/issues/16113

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
**Preface:** One of the main "microstructures" of the code we use is chaining methods-with-blocks; and we really love to keep those blocks DRY when they are simple. Currently, for DRY-ing up simple blocks, we have:

* `foo(&:symbol)`
* `foo(&some.method(:name))` (as of 2.7, `foo(&some.:name)`)
* Currently disputed "nameless block args": `foo { something(@1) }` or `foo { something(@) }` or `foo { something(it) }`

**Proposal:** I argue that short and easy-to-remember partial application of blocks and methods can make methods-with-blocks much more pleasant and consistent to write, and continue softly shifting Ruby towards "functional" (while staying true to language's spirit). 

In order to achieve this, I propose method `{Symbol,Method,Proc}#w` (from `with`), which will produce `Proc` with _last_ arguments bound.

Example of usability:

```ruby
# No-shortcuts: fetch something and parse as JSON:
fetch(urls).map { |body| JSON.parse(body) }
# Could be already (2.7+) shortened to:
fetch(urls).map(&JSON.:parse)

# But if you have this:
fetch(urls).map { |body| JSON.parse(body, symbolize_names: true) }
# How to shorten it, to don't repeat body?
# "Nameless block args" answer:
fetch(urls).map { JSON.parse(@1, symbolize_names: true) }
# Partial application answer:
fetch(urls).map(&JSON.:parse.w(symbolize_names: true))
```

I believe that the latter (while can be easily met with usual "hard to understand for a complete novice") provides the added value of producing proper "functional object", that can be stored in variables and constants, and generally lead to new approaches to writing Ruby code. 

Another example:
```ruby
(6..11).map(&:**.w(2)).map(&:clamp.w(20, 50))
# => [36, 49, 50, 50, 50, 50]
```

Reference implementation:
```ruby
class Symbol
  def w(*args)
    proc { |receiver, *rest| receiver.send(self, *rest, *args) }
  end
end

class Method
  def w(*args)
    proc { |receiver, *rest| self.call(receiver, *rest, *args) }
  end
end

class Proc
  def w(*args)
    prc = self
    proc { |*rest| prc.call(*rest, *args) }
  end
end
```



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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ruby-core:94433] [Ruby master Feature#16113] Partial application
       [not found] <redmine.issue-16113.20190819100716@ruby-lang.org>
  2019-08-19 10:07 ` [ruby-core:94432] [Ruby master Feature#16113] Partial application zverok.offline
@ 2019-08-19 11:11 ` shevegen
  2019-08-19 12:23 ` [ruby-core:94434] " hanmac
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 6+ messages in thread
From: shevegen @ 2019-08-19 11:11 UTC (permalink / raw)
  To: ruby-core

Issue #16113 has been updated by shevegen (Robert A. Heiler).


Personally I dislike this proposal primarily due to the name alone. I don't think
a method named .m is good in this context.

We do have short named methods here and there, of course, such as "p" or "pp",
but I feel that these cases are simpler, and relate mostly to "output-related
tasks".

To me it is not clear why a method called "m" should signify "partial application".

There are a few other aspects intermingled in the proposal, or comments that 
I think are a bit strange.

For example:

    foo(&some.method(:name)) (as of 2.7, foo(&some.:name))
    Currently disputed "nameless block args": foo { something(@1) } or foo { something(@) } or foo { something(it) }

First, I don't think the second is "disputed", but let's ignore this for
the moment. To me, foo(&some.method(:name)) has little to do with e. g.
foo { method(@1) }. Both syntax-wise and from the functionality; but 
syntax-wise, I actually think that ALL the syntax examples are not hugely
elegant. Neither is the oldschool foo(&:symbol). I use the latter myself,
mostly because it leads to shorter code, but I think it is visually not
as elegant as the longer block variant:

    .each {|foo|
    }

In my opinion, this style is the clearest. Not as short as & but clearer
and cleaner, in my opinion. But I digress.

Another part of the proposal mentioned the "staying true to language's
spirit". I think this is a bit problematic, though. Ruby was always 
multi-paradigm and had influences from different languages. My own opinion
is that ruby's biggest strength is the focus on OOP, but I think this may
depend a lot on how someone may use ruby. My use cases will be different
from what other people use. There is also a lot of ruby code out in the 
wild I would never write, use or want to maintain. :)

Some of these coding styles are, IMO, somewhat orthogonal or opposing to
one another if applied at the same time. But this is admittedly also a
LOT due to the individual preference of the ruby user at hand.

Another aspect that I dislike is that suggestions like this, but also
similar ones, increase the complexity of ruby by a LOT.

Consider this:

    fetch(urls).map(&JSON.:parse.w(symbolize_names: true))

Honestly, I don't even want to have to get my brain to want to 
decipher this. Again, this is up to a personal opinion and preference,
just as people may appreciate a shorter syntax to block parameters
or dislike it - but if possible, I think it would be better to strive
for simplicity rather than build up more and more complexity into
ruby in general.

This is of course only my own personal opinion on that matter.

Note that using a slightly different name other than e. g. w,
may partially alleviate the above problem, but the syntax complexity
and overall complexity may still remain.

IMO I think this is simply for matz to decide how much complexity 
ruby should strive to in general.

This is also, as stated, up to an individual's preference - zverok
loves deeply nested, chained blocks. I prefer them to be much 
much simpler, including syntax. Difficult to unite two somewhat
opposing views on the same topic. :D

----------------------------------------
Feature #16113: Partial application
https://bugs.ruby-lang.org/issues/16113#change-80858

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
**Preface:** One of the main "microstructures" of the code we use is chaining methods-with-blocks; and we really love to keep those blocks DRY when they are simple. Currently, for DRY-ing up simple blocks, we have:

* `foo(&:symbol)`
* `foo(&some.method(:name))` (as of 2.7, `foo(&some.:name)`)
* Currently disputed "nameless block args": `foo { something(@1) }` or `foo { something(@) }` or `foo { something(it) }`

**Proposal:** I argue that short and easy-to-remember partial application of blocks and methods can make methods-with-blocks much more pleasant and consistent to write, and continue softly shifting Ruby towards "functional" (while staying true to language's spirit). 

In order to achieve this, I propose method `{Symbol,Method,Proc}#w` (from `with`), which will produce `Proc` with _last_ arguments bound.

Example of usability:

```ruby
# No-shortcuts: fetch something and parse as JSON:
fetch(urls).map { |body| JSON.parse(body) }
# Could be already (2.7+) shortened to:
fetch(urls).map(&JSON.:parse)

# But if you have this:
fetch(urls).map { |body| JSON.parse(body, symbolize_names: true) }
# How to shorten it, to don't repeat body?
# "Nameless block args" answer:
fetch(urls).map { JSON.parse(@1, symbolize_names: true) }
# Partial application answer:
fetch(urls).map(&JSON.:parse.w(symbolize_names: true))
```

I believe that the latter (while can be easily met with usual "hard to understand for a complete novice") provides the added value of producing proper "functional object", that can be stored in variables and constants, and generally lead to new approaches to writing Ruby code. 

Another example:
```ruby
(6..11).map(&:**.w(2)).map(&:clamp.w(20, 50))
# => [36, 49, 50, 50, 50, 50]
```

Reference implementation:
```ruby
class Symbol
  def w(*args)
    proc { |receiver, *rest| receiver.send(self, *rest, *args) }
  end
end

class Method
  def w(*args)
    proc { |receiver, *rest| self.call(receiver, *rest, *args) }
  end
end

class Proc
  def w(*args)
    prc = self
    proc { |*rest| prc.call(*rest, *args) }
  end
end
```



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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ruby-core:94434] [Ruby master Feature#16113] Partial application
       [not found] <redmine.issue-16113.20190819100716@ruby-lang.org>
  2019-08-19 10:07 ` [ruby-core:94432] [Ruby master Feature#16113] Partial application zverok.offline
  2019-08-19 11:11 ` [ruby-core:94433] " shevegen
@ 2019-08-19 12:23 ` hanmac
  2019-08-20  1:28 ` [ruby-core:94440] " shannonskipper
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 6+ messages in thread
From: hanmac @ 2019-08-19 12:23 UTC (permalink / raw)
  To: ruby-core

Issue #16113 has been updated by Hanmac (Hans Mackowiak).


the Devs should maybe look at `#curry` for this, currently it doesn't support a way to curry keyword arguments

----------------------------------------
Feature #16113: Partial application
https://bugs.ruby-lang.org/issues/16113#change-80859

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
**Preface:** One of the main "microstructures" of the code we use is chaining methods-with-blocks; and we really love to keep those blocks DRY when they are simple. Currently, for DRY-ing up simple blocks, we have:

* `foo(&:symbol)`
* `foo(&some.method(:name))` (as of 2.7, `foo(&some.:name)`)
* Currently disputed "nameless block args": `foo { something(@1) }` or `foo { something(@) }` or `foo { something(it) }`

**Proposal:** I argue that short and easy-to-remember partial application of blocks and methods can make methods-with-blocks much more pleasant and consistent to write, and continue softly shifting Ruby towards "functional" (while staying true to language's spirit). 

In order to achieve this, I propose method `{Symbol,Method,Proc}#w` (from `with`), which will produce `Proc` with _last_ arguments bound.

Example of usability:

```ruby
# No-shortcuts: fetch something and parse as JSON:
fetch(urls).map { |body| JSON.parse(body) }
# Could be already (2.7+) shortened to:
fetch(urls).map(&JSON.:parse)

# But if you have this:
fetch(urls).map { |body| JSON.parse(body, symbolize_names: true) }
# How to shorten it, to don't repeat body?
# "Nameless block args" answer:
fetch(urls).map { JSON.parse(@1, symbolize_names: true) }
# Partial application answer:
fetch(urls).map(&JSON.:parse.w(symbolize_names: true))
```

I believe that the latter (while can be easily met with usual "hard to understand for a complete novice") provides the added value of producing proper "functional object", that can be stored in variables and constants, and generally lead to new approaches to writing Ruby code. 

Another example:
```ruby
(6..11).map(&:**.w(2)).map(&:clamp.w(20, 50))
# => [36, 49, 50, 50, 50, 50]
```

Reference implementation:
```ruby
class Symbol
  def w(*args)
    proc { |receiver, *rest| receiver.send(self, *rest, *args) }
  end
end

class Method
  def w(*args)
    proc { |receiver, *rest| self.call(receiver, *rest, *args) }
  end
end

class Proc
  def w(*args)
    prc = self
    proc { |*rest| prc.call(*rest, *args) }
  end
end
```



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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ruby-core:94440] [Ruby master Feature#16113] Partial application
       [not found] <redmine.issue-16113.20190819100716@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2019-08-19 12:23 ` [ruby-core:94434] " hanmac
@ 2019-08-20  1:28 ` shannonskipper
  2019-08-23 23:51 ` [ruby-core:94517] " shannonskipper
  2019-08-24 10:57 ` [ruby-core:94529] " zverok.offline
  5 siblings, 0 replies; 6+ messages in thread
From: shannonskipper @ 2019-08-20  1:28 UTC (permalink / raw)
  To: ruby-core

Issue #16113 has been updated by shan (Shannon Skipper).


An aside, but I took a stab at a pure Ruby implementation of keyword argument currying: https://gist.github.com/havenwood/db041566abeac894602c188c77374040

``` ruby
['{"aim":true}', '{"impossible":false}'].map &JSON.:parse.curry.(symbolize_names: true)
#=> [{:aim=>true}, {:impossible=>false}]
```


----------------------------------------
Feature #16113: Partial application
https://bugs.ruby-lang.org/issues/16113#change-80866

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
**Preface:** One of the main "microstructures" of the code we use is chaining methods-with-blocks; and we really love to keep those blocks DRY when they are simple. Currently, for DRY-ing up simple blocks, we have:

* `foo(&:symbol)`
* `foo(&some.method(:name))` (as of 2.7, `foo(&some.:name)`)
* Currently disputed "nameless block args": `foo { something(@1) }` or `foo { something(@) }` or `foo { something(it) }`

**Proposal:** I argue that short and easy-to-remember partial application of blocks and methods can make methods-with-blocks much more pleasant and consistent to write, and continue softly shifting Ruby towards "functional" (while staying true to language's spirit). 

In order to achieve this, I propose method `{Symbol,Method,Proc}#w` (from `with`), which will produce `Proc` with _last_ arguments bound.

Example of usability:

```ruby
# No-shortcuts: fetch something and parse as JSON:
fetch(urls).map { |body| JSON.parse(body) }
# Could be already (2.7+) shortened to:
fetch(urls).map(&JSON.:parse)

# But if you have this:
fetch(urls).map { |body| JSON.parse(body, symbolize_names: true) }
# How to shorten it, to don't repeat body?
# "Nameless block args" answer:
fetch(urls).map { JSON.parse(@1, symbolize_names: true) }
# Partial application answer:
fetch(urls).map(&JSON.:parse.w(symbolize_names: true))
```

I believe that the latter (while can be easily met with usual "hard to understand for a complete novice") provides the added value of producing proper "functional object", that can be stored in variables and constants, and generally lead to new approaches to writing Ruby code. 

Another example:
```ruby
(6..11).map(&:**.w(2)).map(&:clamp.w(20, 50))
# => [36, 49, 50, 50, 50, 50]
```

Reference implementation:
```ruby
class Symbol
  def w(*args)
    proc { |receiver, *rest| receiver.send(self, *rest, *args) }
  end
end

class Method
  def w(*args)
    proc { |receiver, *rest| self.call(receiver, *rest, *args) }
  end
end

class Proc
  def w(*args)
    prc = self
    proc { |*rest| prc.call(*rest, *args) }
  end
end
```



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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ruby-core:94517] [Ruby master Feature#16113] Partial application
       [not found] <redmine.issue-16113.20190819100716@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2019-08-20  1:28 ` [ruby-core:94440] " shannonskipper
@ 2019-08-23 23:51 ` shannonskipper
  2019-08-24 10:57 ` [ruby-core:94529] " zverok.offline
  5 siblings, 0 replies; 6+ messages in thread
From: shannonskipper @ 2019-08-23 23:51 UTC (permalink / raw)
  To: ruby-core

Issue #16113 has been updated by shan (Shannon Skipper).


I like Hanmac's idea.

``` ruby
Klass.:meth.curry.()
```

Seems very close to:

``` ruby
Klass.:meth.w()
```
 
 I know its previously been said that `#curry` is a bit of an easter egg. Would it be acceptable to add keyword argument support for `#curry`?

@zverok If `#curry` gets support for keyword arguments, would it suffice for this case or do you think `#w` would still be called for?

----------------------------------------
Feature #16113: Partial application
https://bugs.ruby-lang.org/issues/16113#change-80953

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
**Preface:** One of the main "microstructures" of the code we use is chaining methods-with-blocks; and we really love to keep those blocks DRY when they are simple. Currently, for DRY-ing up simple blocks, we have:

* `foo(&:symbol)`
* `foo(&some.method(:name))` (as of 2.7, `foo(&some.:name)`)
* Currently disputed "nameless block args": `foo { something(@1) }` or `foo { something(@) }` or `foo { something(it) }`

**Proposal:** I argue that short and easy-to-remember partial application of blocks and methods can make methods-with-blocks much more pleasant and consistent to write, and continue softly shifting Ruby towards "functional" (while staying true to language's spirit). 

In order to achieve this, I propose method `{Symbol,Method,Proc}#w` (from `with`), which will produce `Proc` with _last_ arguments bound.

Example of usability:

```ruby
# No-shortcuts: fetch something and parse as JSON:
fetch(urls).map { |body| JSON.parse(body) }
# Could be already (2.7+) shortened to:
fetch(urls).map(&JSON.:parse)

# But if you have this:
fetch(urls).map { |body| JSON.parse(body, symbolize_names: true) }
# How to shorten it, to don't repeat body?
# "Nameless block args" answer:
fetch(urls).map { JSON.parse(@1, symbolize_names: true) }
# Partial application answer:
fetch(urls).map(&JSON.:parse.w(symbolize_names: true))
```

I believe that the latter (while can be easily met with usual "hard to understand for a complete novice") provides the added value of producing proper "functional object", that can be stored in variables and constants, and generally lead to new approaches to writing Ruby code. 

Another example:
```ruby
(6..11).map(&:**.w(2)).map(&:clamp.w(20, 50))
# => [36, 49, 50, 50, 50, 50]
```

Reference implementation:
```ruby
class Symbol
  def w(*args)
    proc { |receiver, *rest| receiver.send(self, *rest, *args) }
  end
end

class Method
  def w(*args)
    proc { |receiver, *rest| self.call(receiver, *rest, *args) }
  end
end

class Proc
  def w(*args)
    prc = self
    proc { |*rest| prc.call(*rest, *args) }
  end
end
```



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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [ruby-core:94529] [Ruby master Feature#16113] Partial application
       [not found] <redmine.issue-16113.20190819100716@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2019-08-23 23:51 ` [ruby-core:94517] " shannonskipper
@ 2019-08-24 10:57 ` zverok.offline
  5 siblings, 0 replies; 6+ messages in thread
From: zverok.offline @ 2019-08-24 10:57 UTC (permalink / raw)
  To: ruby-core

Issue #16113 has been updated by zverok (Victor Shepelev).


> If `#curry` gets support for keyword arguments, would it suffice for this case

I don't think so, unfortunately. 

1. Of my examples, it covers only `JSON.parse`
  * It doesn't cover non-keyword arguments, which, I believe, it should. Example: `construct_filename.then(&File.:read.w('rb'))`
  * It doesn't cover symbol partial application. While it *could* be seen as "esotheric" by some, but in realistic code, there are pretty regular demand for something like `numbers.map(&:+.w(2))`. I once [proposed](https://bugs.ruby-lang.org/issues/15301) the `numbers.map(&:+.(2))` syntax, which is "nice-looking", but semantically incorrect
2. While "conceptually true to functional programming", it is just *too long*, which kinda undermines the whole point.

----------------------------------------
Feature #16113: Partial application
https://bugs.ruby-lang.org/issues/16113#change-80971

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
**Preface:** One of the main "microstructures" of the code we use is chaining methods-with-blocks; and we really love to keep those blocks DRY when they are simple. Currently, for DRY-ing up simple blocks, we have:

* `foo(&:symbol)`
* `foo(&some.method(:name))` (as of 2.7, `foo(&some.:name)`)
* Currently disputed "nameless block args": `foo { something(@1) }` or `foo { something(@) }` or `foo { something(it) }`

**Proposal:** I argue that short and easy-to-remember partial application of blocks and methods can make methods-with-blocks much more pleasant and consistent to write, and continue softly shifting Ruby towards "functional" (while staying true to language's spirit). 

In order to achieve this, I propose method `{Symbol,Method,Proc}#w` (from `with`), which will produce `Proc` with _last_ arguments bound.

Example of usability:

```ruby
# No-shortcuts: fetch something and parse as JSON:
fetch(urls).map { |body| JSON.parse(body) }
# Could be already (2.7+) shortened to:
fetch(urls).map(&JSON.:parse)

# But if you have this:
fetch(urls).map { |body| JSON.parse(body, symbolize_names: true) }
# How to shorten it, to don't repeat body?
# "Nameless block args" answer:
fetch(urls).map { JSON.parse(@1, symbolize_names: true) }
# Partial application answer:
fetch(urls).map(&JSON.:parse.w(symbolize_names: true))
```

I believe that the latter (while can be easily met with usual "hard to understand for a complete novice") provides the added value of producing proper "functional object", that can be stored in variables and constants, and generally lead to new approaches to writing Ruby code. 

Another example:
```ruby
(6..11).map(&:**.w(2)).map(&:clamp.w(20, 50))
# => [36, 49, 50, 50, 50, 50]
```

Reference implementation:
```ruby
class Symbol
  def w(*args)
    proc { |receiver, *rest| receiver.send(self, *rest, *args) }
  end
end

class Method
  def w(*args)
    proc { |receiver, *rest| self.call(receiver, *rest, *args) }
  end
end

class Proc
  def w(*args)
    prc = self
    proc { |*rest| prc.call(*rest, *args) }
  end
end
```



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

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-08-24 10:57 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <redmine.issue-16113.20190819100716@ruby-lang.org>
2019-08-19 10:07 ` [ruby-core:94432] [Ruby master Feature#16113] Partial application zverok.offline
2019-08-19 11:11 ` [ruby-core:94433] " shevegen
2019-08-19 12:23 ` [ruby-core:94434] " hanmac
2019-08-20  1:28 ` [ruby-core:94440] " shannonskipper
2019-08-23 23:51 ` [ruby-core:94517] " shannonskipper
2019-08-24 10:57 ` [ruby-core:94529] " zverok.offline

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).