Стрелки II
Aug. 12th, 2011 01:37 amСамое важное сказать забыл. Зачем на практике концепция стрелок нужна, если все равно аппликабельные стрелки эквивалентны по выразительности монадам.
А дело всё в том, что структура стрелок позволяет определять узнать, в каких случаях порядок выполнения менять можно, а в каких нельзя. Предположим, кроме чистых функций у нас в программе встречаются операции Reader(state) и Accessor(state). Кроме того известно, что кроме последних никто state не меняет.
Если пользоваться подходом стрелок, то все наши операции вместе живут в категории Accessor(state)-стрелок, структура которая кодирует тот факт, что между каждыми двумя последовательными выполнениями операции Writer(state) порядок Reader(state)-операций можно произвольно менять. Стрелки
^get("given name") >>> ^swap >>> ^get("surname") >>> ^join(" ") >>> set("full name")
и
^get("surname") >>> ^swap >>> ^get("given name") >>> ^join(" ") >>> set("full name")
оказываются попросту равны, в то время как при использовании обыкновенного монадного склеивания, получаются цепи, имеющие по построению жёсткий порядок.
Этот факт отражается и на возможностях комбинирования: монадные комбинаторы имеют жёсткий порядок даже если кодируемые ими эффекты взаимно независимы, а некоторые монады не комбинируются в принципе. Исторически стрелки были введены именно из-за того, что парсер, написанный на монадах, жрал сотни памяти, потому что ненужные ветви выполнения не могли быть пожраны сборщиком мусора. Из-за жёсткости монадных цепочек, натурально. Оператор >>= should be considered harmful.
Увы, хаскелловская do-нотация для стрелок хороша только, если мы занимаемся data circuitry, для случая аппликабельных стрелок (99% случаев на практике) она непрактична.
А дело всё в том, что структура стрелок позволяет определять узнать, в каких случаях порядок выполнения менять можно, а в каких нельзя. Предположим, кроме чистых функций у нас в программе встречаются операции Reader(state) и Accessor(state). Кроме того известно, что кроме последних никто state не меняет.
Если пользоваться подходом стрелок, то все наши операции вместе живут в категории Accessor(state)-стрелок, структура которая кодирует тот факт, что между каждыми двумя последовательными выполнениями операции Writer(state) порядок Reader(state)-операций можно произвольно менять. Стрелки
^get("given name") >>> ^swap >>> ^get("surname") >>> ^join(" ") >>> set("full name")
и
^get("surname") >>> ^swap >>> ^get("given name") >>> ^join(" ") >>> set("full name")
оказываются попросту равны, в то время как при использовании обыкновенного монадного склеивания, получаются цепи, имеющие по построению жёсткий порядок.
Этот факт отражается и на возможностях комбинирования: монадные комбинаторы имеют жёсткий порядок даже если кодируемые ими эффекты взаимно независимы, а некоторые монады не комбинируются в принципе. Исторически стрелки были введены именно из-за того, что парсер, написанный на монадах, жрал сотни памяти, потому что ненужные ветви выполнения не могли быть пожраны сборщиком мусора. Из-за жёсткости монадных цепочек, натурально. Оператор >>= should be considered harmful.
Увы, хаскелловская do-нотация для стрелок хороша только, если мы занимаемся data circuitry, для случая аппликабельных стрелок (99% случаев на практике) она непрактична.