Как это работает
Да, foldp
хранит какое-то внутреннее состояние. Сохранение всей истории было бы расточительным и не делается.
Если вы используете foldp
несколько раз в своем коде, выполняя разные действия или получая разные входные сигналы, то каждый экземпляр будет сохранять свое собственное локальное состояние. Пример:
import Keyboard
plus = (foldp (\dir presses -> presses + dir.x) 0 Keyboard.arrows)
minus = (foldp (\dir presses -> presses - dir.x) 0 Keyboard.arrows)
showThem p m = flow down (map asText [p, m])
main = lift2 showThem plus minus
Но если вы дважды используете результирующий сигнал от foldp, в вашей скомпилированной программе будет только один экземпляр foldp, результирующие изменения просто будут использованы в двух местах:
import Keyboard
plus = (foldp (\dir presses -> presses + dir.x) 0 Keyboard.arrows)
showThem p m = flow down (map asText [p, m])
main = lift2 showThem plus plus
Главный вопрос
Если это действительно так, то не является ли это нарушением принципов функционального программирования, поскольку main теперь поддерживает внутреннее состояние (или, по крайней мере, foldp
)?
У функционального программирования нет какого-то канонического определения, которым бы пользовались все. Есть много примеров функциональных языков программирования, которые позволяют использовать изменяемое состояние. Некоторые из этих языков программирования показывают вам, что значение может быть изменено в системе типов (вы можете видеть тип State a
Haskell как таковой, хотя это действительно зависит от вашей точки зрения).
Но что такое изменчивое состояние? Что такое изменяемое значение? Это значение внутри программы, которое можно изменить. То есть может измениться. Это могут быть разные вещи в разное время. Ах, но мы же знаем, как Elm называет значения изменяющимися с течением времени! Это Signal
.
Так что на самом деле Signal
в Elm — это значение, которое может меняться со временем, и поэтому его можно рассматривать как переменную, изменяемое значение или изменяемое состояние. Просто мы очень строго управляем этим значением, разрешая только несколько хорошо выбранных манипуляций с Signal
s. Такие Signal
могут быть основаны на других Signal
в вашей программе, или поступать из библиотеки, или поступать из внешнего мира (подумайте о таких входных данных, как Mouse.position
). И кто знает, как внешний мир дошел до этого сигнала! Таким образом, разрешить вашим собственным Signal
s основываться на прошлом значении Signal
s на самом деле нормально.
Заключение / TL;DR
Вы могли видеть Signal
как защитную оболочку вокруг изменяемого состояния. Мы предполагаем, что сигналы, поступающие из внешнего мира (в качестве входных данных для вашей программы), непредсказуемы, но поскольку у нас есть эта защитная оболочка, которая разрешает только подъем/выборку/фильтрацию/складывание, программа, которую вы пишете, в остальном полностью предсказуема. Побочные эффекты сдерживаются и управляются, поэтому я думаю, что это все еще «функциональное программирование».
person
Apanatshka
schedule
26.07.2014