Подтвердить что ты не робот

Почему Scala нужен без параметров в дополнение к методам нулевого параметра?

Я понимаю разницу между методами с нулевым параметром и без параметров, но то, что я действительно не понимаю, - это выбор дизайна языка, который делал необязательные методы.

Недостатки, о которых я могу думать:

  • Это сбивает с толку. Каждую неделю или две есть вопросы здесь или в списке рассылки Scala.
  • Это сложно; мы также должны различать () => X и => X.
  • Это двусмысленно: x.toFoo(y) означает, что он говорит, или x.toFoo.apply(y)? (Ответ: это зависит от того, какие перегрузки имеют метод x toFoo и перегрузки по методу Foo apply, но если есть столкновение, вы не видите ошибку, пока не попытаетесь ее вызвать.)
  • Это испортит синтаксис метода метода operator style: вместо аргументов, методов цепочки или в конце, чтобы избежать помех с точкой с запятой, нет символа. С помощью методов zero-arg вы можете использовать пустой список параметров ().

В настоящее время вы не можете иметь оба определения в классе: вы получаете сообщение об ошибке, когда метод уже определен. Они также преобразуются в Function0.

Почему бы просто не сделать методы def foo и def foo() точно такими же и разрешить их вызывать с круглыми скобками или без них? Каковы его особенности?

4b9b3361

Ответ 1

Currying, That Why

Даниэль отлично поработал, объясняя, почему нужны беспараметрические методы. Я объясню, почему они отчетливо рассматриваются методами нулевого параметра.

Многие люди рассматривают различие между параметрами без параметров и функциями с нулевым параметром в виде нечеткой формы синтаксического сахара. По правде говоря, это просто артефакт о том, как Scala поддерживает каррирование (для полноты, см. Ниже более подробное объяснение того, что такое каррирование, и почему нам все это так нравится).

Формально функция может иметь ноль или более списков параметров с нулевым или большим количеством параметров.
Это означает, что допустимы следующие значения: def a, def b(), а также изобретенные def c()() и def d(x: Int)()()(y: Int) и т.д.

Функция def foo = ??? имеет нулевые списки параметров. Функция def bar() = ??? имеет только один список параметров с нулевыми параметрами. Введение дополнительных правил, которые объединяют две формы, подорвало бы каррирование как согласованное языковое средство: def a было бы эквивалентно по форме def b() и def c()() для обоих; def d(x: Int)()()(y: Int) будет эквивалентен def e()(x: Int)(y: Int)()().

Один случай, когда currying не имеет значения, - это когда вы работаете с Java interop. Java не поддерживает currying, поэтому нет проблем с внедрением синтаксического сахара для методов с нулевым параметром, таких как "test".length() (который непосредственно вызывает java.lang.String#length()), также вызывается как "test".length.

Краткое объяснение каррирования

Scala поддерживает функцию языка, называемую "currying", названную в честь математика Хаскелла Карри.
Currying позволяет вам определять функции с несколькими списками параметров, например:

def add(a: Int)(b: Int): Int = a + b
add(2)(3) // 5

Это полезно, потому что теперь вы можете определить inc в части частичного применения add:

def inc: Int => Int = add(1)
inc(2) // 3

Каррирование чаще всего рассматривается как способ введения структур управления через библиотеки, например:

def repeat(n: Int)(thunk: => Any): Unit = (1 to n) foreach { _ => thunk }

repeat(2) {
  println("Hello, world")
}

// Hello, world
// Hello, world

В качестве примера, см., как repeat открывает еще одну возможность использования currying:

def twice: (=> Any) => Unit = repeat(2)

twice {
  println("Hello, world")
}

// ... you get the picture :-)

Ответ 2

Одна хорошая вещь о проблеме, периодически возникающей в ML, заключается в том, что существуют периодические ответы.

Кто может сопротивляться потоку, называемому "Что с нами не так?"

https://groups.google.com/forum/#!topic/scala-debate/h2Rej7LlB2A

От: martin odersky Дата: Пт, 2 мар 2012 в 12:13 PM Тема: Re: [ scala -debate] что с нами не так...

То, что некоторые люди считают "неправильным с нами", состоит в том, что мы пытаемся сгибать назад, чтобы заставить идиомы Java работать плавно в Scala. принципиальная вещь заключалась бы в том, чтобы сказать def length() и def length разные, и, извините, String - это класс Java, поэтому вам нужно написать s.length(), а не s.length. Мы очень усердно работаем над допускающие автоматические преобразования от s.length до s.length(). Это проблематичным, как есть. Обобщая, что так, чтобы эти два были идентифицированы в системе типов будет верным способом обречения. Как тогда вы неоднозначность:

type Action =() = > () def foo: Действие

Является ли foo типа Action или()? Как насчет foo()?

Martin

Мой любимый фрагмент фиаско из этой темы:

On Fri, Mar 2, 2012 at 10:15 AM, Rex Kerr <[email protected]> wrote:

>This would leave you unable to distinguish between the two with 
>structural types, but how often is the case when you desperately 
>want to distinguish the two compared to the case where distinguishing 
>between the two is a hassle?


/** Note to maintenance programmer: It is important that this method be
 *  callable by classes which have a 'def foo(): Int' but not by classes which
 *  merely have a 'def foo: Int'.  The correctness of this application depends
 *  on maintaining this distinction.
 *  
 *  Additional note to maintenance programmer: I have moved to zambia.
 *  There is no forwarding address.  You will never find me.
 */
def actOnFoo(...)

Таким образом, основной мотивацией для этой функции является генерация такого рода потока ML.

Еще один бит googlology:

В Чт, 1 апреля 2010 в 8:04, Rex Kerr < [скрытое письмо] > написал: On Thu, Apr 1, 2010 at 1:00 PM, richard emberson < [скрытое письмо] > написал:

  

Я предполагаю, что "def getName: String" совпадает с "def getName(): String"

  
  

Нет, на самом деле, это не так. Хотя оба они называют метод   без параметров, один - это "метод с нулевыми списками параметров", тогда как   другой - это "метод с одним пустым списком параметров". Если ты хочешь   быть еще более озадаченным, попробуйте def getName()(): String (и создайте   класс с этой сигнатурой)!

     

Scala представляет параметры как список списков, а не только список и

     

Список()!= Список (Список())

     

Это своего рода причудливое раздражение, тем более, что так мало   различия между ними в противном случае, и поскольку оба могут быть   автоматически превращается в подпись функции() = > String.

True. В самом деле, любая слияния между безпараметрическими методами и методы с пустыми списками параметров полностью связаны с Java interop. Они должны быть разными, но тогда обработка Java-методов будет просто слишком болезненно. Можете ли вы представить, что нужно писать str.length() каждый вы берете длину строки?

Приветствия

Ответ 3

Во-первых, () => X и => X не имеют абсолютно никакого отношения к беспараметрированным методам.

Теперь выглядит довольно глупо писать что-то вроде этого:

var x() = 5
val y() = 2
x() = x() + y()

Теперь, если вы не следите за тем, что приведенное выше имеет отношение к беспараметричным методам, вы должны искать принцип равномерного доступа. Все вышеперечисленное относится к объявлениям методов, и все они могут быть заменены на def. То есть, предполагая, что вы удалите их круглые скобки.

Ответ 4

Я бы сказал, что оба варианта возможны, потому что вы можете обращаться к изменяемому состоянию с помощью метода без параметров:

class X(private var x: Int) {
  def inc() { x += 1 }
  def value = x
}

Метод value не имеет побочных эффектов (он обращается только к изменяемому состоянию). Это поведение явно упоминается в Программирование в Scala:

Такие безпараметрические методы довольно распространены в Scala. Напротив, методы, определяемые пустым скобками, например def height(): Int, называются пустыми методами. Рекомендуемое соглашение заключается в использовании безпараметрического метода, когда нет параметров, и метод обращается к изменяемому состоянию только путем чтения полей содержащего объекта (в частности, он не изменяет изменяемое состояние).

Это соглашение поддерживает принцип единого доступа [...]

Подводя итог, рекомендуется, чтобы стиль в Scala определял методы, которые не принимают никаких параметров и не имеют побочных эффектов в качестве безпараметрических методов, т.е. оставляют пустые круглые скобки. С другой стороны, вы никогда не должны определять метод, который имеет побочные эффекты без круглых скобок, потому что тогда вызовы этого метода будут выглядеть как выбор полей.

Ответ 5

Помимо упомянутого условного факта (побочный эффект и побочный эффект), он помогает в нескольких случаях:

Полезность наличия пустого парнера

// short apply syntax

object A {
  def apply() = 33
}

object B {
  def apply   = 33
}

A()   // works
B()   // does not work

// using in place of a curried function

object C {
  def m()() = ()
}

val f: () => () => Unit = C.m

Полезность наличия no-paren

// val <=> def, var <=> two related defs

trait T { def a:   Int; def a_=(v: Int): Unit }
trait U { def a(): Int; def a_=(v: Int): Unit }

def tt(t: T): Unit = t.a += 1  // works
def tu(u: U): Unit = u.a += 1  // does not work

// avoiding clutter with apply the other way round

object D {
  def a   = Vector(1, 2, 3)
  def b() = Vector(1, 2, 3)
}

D.a(0)  // works
D.b(0)  // does not work

// object can stand for no-paren method

trait E
trait F { def f:   E }
trait G { def f(): E }

object H extends F {
  object f extends E  // works
}

object I extends G {
  object f extends E  // does not work
}

Таким образом, в терминах регулярности языка имеет смысл иметь различие (особенно для последнего показанного случая).