OCaml: Хранение некоторых значений, которые будут использоваться позже, вводит "побочные эффекты"? - PullRequest
8 голосов
/ 28 сентября 2011

Для домашнего задания нам дали указание выполнить задание без каких-либо «побочных эффектов». Я посмотрел «побочные эффекты» на Википедию, и хотя я понимаю, что теоретически это означает «изменяет состояние или имеет наблюдаемое взаимодействие с вызывающими функциями», у меня возникают проблемы с выяснением специфики.

Например, будет ли создание значения, содержащего результат времени некомпиляции, создавать побочные эффекты?

Скажем, у меня было (возможно, синтаксически не идеально):

val myList = (someFunction x y);;
if List.exists ((=) 7) myList then true else false;;

Это может вызвать побочные эффекты? Наверное, я запутался в том, что означает «изменение состояния» в определении побочных эффектов.

Ответы [ 2 ]

8 голосов
/ 28 сентября 2011

Нет;побочный эффект относится, например, к мутации ячейки ref с оператором присваивания := или другим вещам, в которых значение, на которое ссылается имя, изменяется со временем.В этом случае myList является неизменным значением, которое никогда не изменяется во время программы, поэтому оно не имеет эффекта.

См. Также

http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)

5 голосов
/ 28 сентября 2011

Хороший способ думать об этом: «Я изменил что-нибудь, что любой более поздний код (включая повторное выполнение этой же функции позже) мог когда-либо видеть, кроме возвращаемого мной значения?»Если это так, это побочный эффект.Если нет, то вы можете знать, что его нет.

Итак, что-то вроде:

let inc_nosf v = v+1

не имеет побочных эффектов, потому что просто возвращает новое значение, которое на единицу больше, чемцелое число v. Таким образом, если вы выполните следующий код на верхнем уровне ocaml, вы получите соответствующие результаты:

# let x = 5;;
val x : int = 5
# inc_nosf x;;
- : int = 6
# x;;
- : int = 5

Как видите, значение x не изменилось.Итак, так как мы не сохранили возвращаемое значение, то ничего действительно не было увеличено.Наша функция сама изменяет только возвращаемое значение, а не сам x.Таким образом, чтобы сохранить его в x, нам нужно сделать:

# let x = inc_nosf x;;
val x : int = 6
# x;;
- : int = 6

Поскольку функция inc_nosf не имеет побочных эффектов (то есть она взаимодействует только с внешним миром, используя свое возвращаемое значение, а не путемлюбые другие изменения).

Но что-то вроде:

let inc_sf r = r := !r+1

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

# let y = ref 5;;
val y : int ref = {contents = 5}
# inc_sf y;;
- : unit = ()
# y;;
- : int ref = {contents = 6}

Итак, в этом случае, даже если мы все еще не сохраняем возвращаемое значение, оно все равно увеличивается.Это означает, что должны были быть изменения в чем-то, кроме возвращаемого значения.В этом случае этим изменением было назначение с использованием :=, которое изменило сохраненное значение ссылки.

Как хорошее правило, в Ocaml, если вы избегаете использования ссылок, записей, классов, строк,массивов и хеш-таблиц, тогда вы избежите любого риска побочных эффектов.Хотя вы можете безопасно использовать строковые литералы до тех пор, пока вы не будете изменять строку на месте, используя такие функции, как String.set или String.fill.По сути, любая функция, которая может изменить тип данных на месте, вызовет побочный эффект.

...