#performance #if-statement #functional-programming #pattern-matching #ocaml
Вопрос:
Допустим, у нас есть тип под названием d:
type d = D of int * int
И мы хотим провести некоторое сопоставление по шаблону, не лучше ли сделать это таким образом:
let dcmp = function
| D (x, y) when x > y -> 1
| D (x, y) when x < y -> -1
| _ -> 0
или
let dcmp = function
| D (x, y) ->
if x > y then 1 else if x < y then -1 else 0
Просто в общем случае лучше сопоставлять шаблоны со многими случаями «когда» или сопоставлять один шаблон и вставлять в него «если-то-еще»?
И где я могу получить дополнительную информацию о таких вопросах, как передовая практика в OCaml, синтаксические сахара и тому подобное?
Комментарии:
1. С точки зрения функционального программиста Haskell, несколько предложений when делают вещи довольно легко читаемыми, поэтому я бы выбрал это.
2. @vanntile верно, на самом деле я больше ищу возможный эффект, который может оказать использование многих предложений when на время компиляции/выполнения, если есть какой-либо эффект и если он отличается от использования операторов if
3. Мой ответ сосредоточен на руководстве по стилю, для повышения производительности, будем надеяться, что более опытный специалист сможет помочь
4. Не ответ, а замечание. Ваша функция эквивалентна этой:
let dcmp D(x,y) = compare x y
.5. @ghilesZ спасибо, но функция-это всего лишь пример, я ищу общий ответ на вопрос об эффективности «когда против утверждения if».
Ответ №1:
Оба подхода имеют свои плюсы и минусы, поэтому их следует использовать в соответствии с контекстом.
when
Предложение легче понять, чем if
потому, что в нем есть только одна ветвь, поэтому вы можете переварить ветвь за один раз. Это связано с тем, что, когда мы анализируем предложение, чтобы понять его условие пути, мы должны проанализировать все ветви перед ним (и отрицать их), например, сравнить ваш вариант со следующим определением, которое эквивалентно,
let dcmp = function
| D (x, y) when x > y -> 1
| D (x, y) when x = y -> 0
| _ -> -1
Конечно, то же самое верно и для if/then/else
конструкции, просто сложнее случайно переставить ветви (например, во время рефакторинга) в if/then/else
выражении и полностью изменить логику выражения.
Кроме того, when
защита может помешать компилятору выполнить оптимизацию дерева решений 1 и запутать механизм опровержения 2.
Учитывая это, единственным преимуществом использования when
вместо if
в данном конкретном примере является то, что when
синтаксис выглядит более привлекательным, поскольку он идеально выстроен, и человеческому мозгу легче найти, где находятся условия и их соответствующие значения, т. Е. Он больше похож на таблицу истинности. Однако, если мы напишем
let dcmp (D (x,y)) =
if x = y then 0 else
if x > y then 1 else -1
мы можем достичь такого же уровня читабельности.
Подводя итог, его лучше использовать when
, когда невозможно или почти невозможно выразить одним и тем же кодом if/then/else
. Для улучшения читабельности лучше включить вашу логику во вспомогательные функции с удобочитаемыми именами. Например, при dcmp
наилучшем решении не следует использовать ни if
то , ни when
другое, например,
let dcmp (D (x,y)) = compare x y
1)В данном конкретном случае компилятор сгенерирует один и тот же код для when
и if/then/else
. Но в более общих случаях защита может помешать соответствующему компилятору генерировать эффективный код, особенно когда ветви не пересекаются. В нашем случае компилятор просто заметил, что мы повторяем одну и ту же ветвь, объединил их в одну ветвь и превратил ее обратно в выражение if/then/else, например, вот вывод cmm функции с when
защитой,
(if (> x y) 3 (if (< x y) -1 1))
который в точности совпадает с кодом, сгенерированным версией функции if/then/else dcmp
.
2) Не в состояние, в котором он, конечно, не заметит отсутствующую ветвь, а в состояние, в котором он будет сообщать о недостающих ветвях менее точно или попросит вас добавить ненужные ветви.
Комментарии:
1. Я предпочитаю
if x = y then 0 /// else if x > y then 1 /// else -1
(с///
метапозицией для разрывов строк). таким образом, у вас есть три отдельные строки для трех альтернатив.2. это также мой предпочтительный способ структурирования выражений if/then/else, я просто показываю, что можно связать несколько выражений if/then/else таким образом, чтобы это выглядело как таблица истинности. С учетом сказанного, я обычно стараюсь избегать цепочки if/then/else и предпочитаю по возможности включать их в логические предикаты. Это экономит мне много времени и нервов, когда я позже прочитаю свой код 🙂
Ответ №2:
Цитирование руководства OCaml по стилю ясности и изящества:
Код чаще читается, чем пишется — облегчите жизнь читателю
и
Чем меньше кода, тем лучше, а зашифрованный код хуже
Первое заставляет меня думать, что версия с несколькими when
предложениями является лучшим выбором, так как она позволяет легко предсказать или оценить результат при чтении кода в зависимости от условий. Второй идет дальше, против первого if-then-else
, потому что, даже если он короче, загадочен, если смотреть издалека.
Кроме того, в разделе Функции мы узнаем, что «Сопоставление шаблонов является предпочтительным способом определения функций».
С точки зрения функционального программиста Haskell.