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

В сразу после 2:40 в Учебном 3 видео Scala ShadowofCatron, указано, что круглые скобки после названия преобразователя дополнительные. "Buh?" сказал мой мозг функционального программирования, начиная со значения функции и значения он оценивает к при применении совершенно другие вещи.

Таким образом, я записал следующее для испытания этого. Мой мыслительный процесс описан в комментариях.

object Main {

    var counter: Int = 10
    def f(): Int = { counter = counter + 1; counter }

    def runThunk(t: () => Int): Int = { t() }

    def main(args: Array[String]): Unit = {
        val a = f()     // I expect this to mean "apply f to no args"
        println(a)      // and apparently it does

        val b = f       // I expect this to mean "the value f", a function value
        println(b)      // but it's the value it evaluates to when applied to no args
        println(b)      // and the application happens immediately, not in the call

        runThunk(b)     // This is an error: it's not println doing something funny
        runThunk(f)     // Not an error: seems to be val doing something funny
    }

}

 

Соглашаться с проблемой, эта программа Схемы (и консольный дамп, который следует) шоу, что я ожидал, что программа Scala сделает.

(define counter (list 10))
(define f (lambda ()
            (set-car! counter (+ (car counter) 1))
            (car counter)))

(define runThunk (lambda (t) (t)))

(define main (lambda args
               (let ((a (f))
                     (b f))
                 (display a) (newline)
                 (display b) (newline)
                 (display b) (newline)
                 (runThunk b)
                 (runThunk f))))

> (main)
11
#
#
13

 

После прибытия в этот сайт, чтобы спросить об этом, я столкнулся с этим ответом, который сказал мне, как исправить вышеупомянутую программу Scala:

    val b = f _     // Hey Scala, I mean f, not f()

Но подчеркивание 'подсказка' иногда только необходимо. Когда я звоню runThunk(f), никакая подсказка не требуется. Но когда я 'искажаю' f к b с a val затем примените его, это не работает: приложение происходит в val; и даже lazy val прокладывает себе путь, таким образом, это не точка оценки, вызывающей это поведение.

 

Это все оставляет меня с вопросом:

Почему Scala иногда автоматически применяет преобразователей при оценке их?

Это, как я подозреваю, вывод типа? И если так, разве система типов не должна оставаться вне семантики языка?

Действительно ли это - хорошая идея? Программисты Scala применяют преобразователей, а не обращаются к их значениям настолько чаще, что создание parens дополнительного лучше в целом?


Примеры записанное использование Scala 2.8.0RC3, DrScheme 4.0.1 в R5RS.

27
задан Community 23 May 2017 в 12:25
поделиться

4 ответа

Проблема здесь:

Buh?" - сказал мой мозг функционального программирования. мозг, поскольку значение функции и значение, в которое она оценивается при при применении - это совершенно разные вещи.

Да, но вы не объявляли никакой функции.

def f(): Int = { counter = counter + 1; counter }

Вы объявили метод под названием f, который имеет один пустой список параметров и возвращает Int. Метод не является функцией - у него нет значения. Никогда, никогда. Лучшее, что вы можете сделать, это получить экземпляр Method через отражение, что на самом деле совсем не одно и то же.

val b = f _     // Hey Scala, I mean f, not f()

Итак, что же означает f _? Если бы f была функцией, она бы означала саму функцию, но это не тот случай. На самом деле это означает следующее:

val b = () => f()

Другими словами, f _ - это закрытие над вызовом метода. А закрытия реализуются через функции.

Наконец, почему в Scala пустые списки параметров необязательны? Потому что, хотя Scala позволяет декларации типа def f = 5, Java этого не делает. Все методы в Java требуют, по крайней мере, пустого списка параметров. И есть много таких методов, которые в стиле Scala не имели бы никаких параметров (например, length и size). Поэтому, чтобы код выглядел более единообразно в отношении пустого списка параметров, Scala делает их необязательными.

15
ответ дан 28 November 2019 в 05:06
поделиться

В вашем примере

def f(): Int = { counter = counter + 1; counter }

определяет метод, а не функцию. AFAIK в Scala методы переводятся в функции автоматически в зависимости от контекста. Чтобы определить функцию, вы можете написать

val f = () => { counter = counter + 1; counter }

и, думаю, вы получите то, что хотите.

12
ответ дан 28 November 2019 в 05:06
поделиться

Ваше предположение верно - Scala имеет типозависимую семантику в отношении вычисления выражений.

Как и Ruby, он всегда оценивает преобразователи даже без скобок. (Это может иметь преимущества для целей взаимодействия, поскольку вы можете переключать чистые и, возможно, нечистые операции без изменения синтаксиса.)

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

Обратите внимание, что оценка, зависящая от типа, может даже имитировать вызов по имени


. Теперь поведение оценки, зависящее от типа, хорошо или плохо? ... Что ж, это, безусловно, может привести к путанице в таких случаях, как ваш, и больше не кажется, что чистый . Но в большинстве случаев он просто работает , как задумано программистом (делая код более лаконичным) - Итак, скажем, это нормально .

10
ответ дан 28 November 2019 в 05:06
поделиться

Причиной по умолчанию, когда вы пишете:

val b = f

, является оценка функции и присвоение результата b , как вы заметили. Вы можете использовать _ или явно указать тип b :

// These all have the same effect
val b = f _
val b: () => Int = f
val b: Function0[Int] = f
14
ответ дан 28 November 2019 в 05:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: