Нет, в Scala это невозможно.
Однако можно добиться преимуществ производительности за счет мутации на месте в чисто функциональном языке. Например, возьмем функцию, которая обновляет массив чисто функциональным способом:
def update(arr: Array[Int], idx: Int, value: Int): Array[Int] =
arr.take(idx) ++ Array(value) ++ arr.drop(idx + 1)
Нам нужно скопировать массив сюда, чтобы сохранить чистоту. Причина в том, что если бы мы изменили его на месте, то смогли бы наблюдать это после вызова функции:
def update(arr: Array[Int], idx: Int, value: Int): Array[Int] = {
arr(idx) = value
arr
}
Следующий код будет нормально работать с первой реализацией, но сломается со второй:
val arr = Array(1, 2, 3)
assert(arr(1) == 2)
val arr2 = update(arr, 1, 42)
assert(arr2(1) == 42) // so far, so good…
assert(arr(1) == 2) // oh noes!
Решение на чисто функциональном языке состоит в том, чтобы просто запретить последнее утверждение. Если вы не можете наблюдать тот факт, что исходный массив был мутирован, то нет ничего плохого в обновлении массива на месте! Средство для достижения этого называется линейными типами. Линейные значения — это значения, которые можно использовать только один раз. Как только вы передадите линейное значение функции, компилятор не позволит вам использовать его снова, что устраняет проблему.
Я знаю два языка, в которых есть эта функция: ATS и Haskell. Если вам нужны подробности, я бы порекомендовал этот доклад Саймона Пейтона-Джонса, где он объясняет реализацию в Haskell:
https://youtu.be/t0mhvd3-60Y
С тех пор поддержка линейных типов была объединена с GHC: https://www.tweag.io/blog/2020-06-19-linear-types-merged/
person
Matthias Berndt
schedule
14.05.2021
var
, которые вы можете изменить в любой момент; но это не будет чисто функционально. Однако, если переменная является внутренней для какого-либо метода и ее изменение невидимо для внешних пользователей, мы по-прежнему называем этот метод ссылочно-прозрачным, и, таким образом, изменение является просто внутренней (и, возможно, прагматичной) деталью реализации. - person Luis Miguel Mejía Suárez   schedule 14.05.2021var
и локальной мутацией, но на самом деле я надеюсь написать это в Идрисе, где нетvar
, следовательно, чисто функционально. Я спрашиваю и в Scala, потому что, если это возможно в Idris, вероятно, это возможно и в Scala. - person joel   schedule 14.05.2021Ref
, как вы могли бы поделиться некоторым изменяемым состоянием. - person Luis Miguel Mejía Suárez   schedule 14.05.2021IO
возвращает действие для выполнения, и когда вы его выполняете, вы получаете результирующее значение, к которому затем можно получить доступ черезmap
и т. д. Точно так же, возможно ли иметь тип, который означает, что это будет производить новое значение из текущего при выполнении, о чем мы можем рассуждать сейчас черезmap
и т. д. Я ожидаю, что это будет похоже на монаду состояния, но использовать только один адрес памяти - person joel   schedule 14.05.2021Ref
выглядит многообещающе. Вы имеете в виду от кошек? - person joel   schedule 14.05.2021val Inc = IO { i += 1 }
, вы также можете взглянуть наRef
, которая вместо того, чтобы позволить вам изменять что-то само по себе, а скорее позволяет вам поделиться некоторыми ( mutable) в нескольких (параллельных) операциях, хотя на самом деле это не дает вам доступа для изменения значения, но дает вам возможность создать новое состояние, учитывая предыдущее и внутренне он может (в cats-effect да) изменять один и тот же адрес памяти. - person Luis Miguel Mejía Suárez   schedule 14.05.2021IO
, который описывает мутацию на месте, как в моем примере. - person Luis Miguel Mejía Suárez   schedule 14.05.2021def foo() = x+1
иx
изменяемы и видны за пределамиfoo
, тоfoo
не является прозрачным с точки зрения ссылок. Следовательно, мутация чисто функциональным путем бессмысленна. Можно ли поджарить кусок льда, чтобы он не растаял? - person Dima   schedule 14.05.2021ST
-монады. Я знаю, что это существует, но я никогда не использовал его ни для чего. - person Andrey Tyukin   schedule 15.05.2021ST
не имеет смысла в Scala,ST
в основном простоvar
- person Luis Miguel Mejía Suárez   schedule 15.05.2021var
. Речь идет о доказательстве того, что ссылки на этотvar
не ускользают. - person Andrey Tyukin   schedule 15.05.2021def thisIsNotFP(): IO[Unit] = { executeSideEffects(); IO.unit }
- person Luis Miguel Mejía Suárez   schedule 15.05.2021println("whatever, wherever")
, не в этом дело. - person Andrey Tyukin   schedule 15.05.2021