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

Я пытался обернуть голову вокруг функционального программирования некоторое время теперь? Я искал лямбда-исчисление, LISP, OCML, F# и даже комбинаторная логика, но основная проблема я имею, - то, как Вы делаете вещи, которые требуют побочных эффектов как (взаимодействующий с пользователем, общаясь с удаленным сервисом, или даже обработайте моделирование с помощью случайной выборки), не нарушая фундаментальную предпосылку чистого функционального программирования, которое является, которые для данного вводят вывод, детерминировано? Я надеюсь, что имею смысл, если не я приветствую какие-либо попытки правильно обучить меня. Заранее спасибо.

17
задан R. Martinho Fernandes 16 December 2009 в 18:59
поделиться

9 ответов

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

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

Аналогичная перспектива состоит в том, чтобы объявить, что вводом в функцию является «полное состояние внешнего мира» и что оценка функции возвращает новое, измененное » f3) нет ничего, что могло бы определять порядок, в котором они будут оцениваться. С другой стороны, если вы позволите каждой функции принимать другую функцию в качестве аргумента, вы можете связать их следующим образом: f1 (f2 (f3 ())) , и в этом случае вы знаете, что f3 будет оцениваться первым, потому что оценка f2 зависит от его значения. [ Изменить: См. Также комментарий ниже о ленивом и нетерпеливом оценивании. Это важно, потому что ленивое вычисление на самом деле довольно распространено в очень чистых контекстах; например, стандартная реализация рекурсии в чистом лямбда-исчислении не является окончательной при энергичной оценке.]

Опять же, чтобы написать интерактивную программу в лямбда-исчислении, вы, вероятно, сделали бы это именно так. Если вам нужно что-то действительно пригодное для программирования, вы

20
ответ дан 30 November 2019 в 10:49
поделиться

Haskell is a pure functional programming language. In Haskell all functions are pure (i.e. they always give the same output for the same inputs). But how do you handle side-effects in Haskell? Well, this problem is beautifully solved through the use of monads.

Taking I/O as an example. In Haskell every function that does I/O returns an IO computation, i.e. a computation in the IO monad. So, for instance, a function that reads an int from the keyboard, instead of returning an int, returns an IO computation that yields an int when it is run:

askForInt :: String -> IO Int

Because it returns an I/O computation instead of an Int, you cannot use this result directly in a sum, for example. In order to access the Int value you need to "unwrap" the computation. The only way to do this is to use the bind function (>>=):

(>>=) :: IO a -> (a -> IO b) -> IO b

Because this also returns an IO computation, you always end up with an I/O computation. This is how Haskell isolates side-effects. The IO monad acts as an abstraction of the state of the real world (in fact under the covers it is usually implemented with a type named RealWorld for the state part).

9
ответ дан 30 November 2019 в 10:49
поделиться

Functional Programming is about limiting & isolating side-effects, not trying to get entirely rid of them... because you can't.

... and yes I find FP useful (certainly with Erlang anyways): I find it is easier to get from "idea" to "program" (or problem to solution ;)... but of course that could just be me.

5
ответ дан 30 November 2019 в 10:49
поделиться

You need to know at least another essential concept: Monads. You will need this to do I/O and the other "useful" stuff!

2
ответ дан 30 November 2019 в 10:49
поделиться

Interacting with a user and communicating with a remote service do require some sort of non-functional part to your software.

Many "functional languages", (like most Lisps) are not purely functional. They still let you do things with side-effects, though side-effecty things are "discouraged" in most contexts.

Haskell is "purely functional" but still lets you do non-functional things via the IO monad. The basic idea is that your purely functional program emits a lazy data structure which is evaluated by a non-functional program (which you don't write, it's part of the environment). One could argue that this data structure itself is an imperative program. So you're sort of doing imperative meta-programming in a functional language.

Ignoring which approach is "better", the goal in both cases is to create a separation between the functional and non-functional parts of your programs, and to limit the size of the non-functional parts as much as possible. The functional parts tend to be more reusable, testable, and easier to reason about.

7
ответ дан 30 November 2019 в 10:49
поделиться

The way Haskell does it is by using monads see wikipedia and the explanation by Haskell on their page.

Basically the idea is that you do not get rid of the IO monad. My understanding is that you are able to chain functions that unwrap an IO monad and execute that function. But you are not able to remove the IO monad altogether.

Another example using monads that is not directly tied to IO is the Maybe Monad. This monad is 'unwrappable' in contrary to the IO monad. But it is easier to explain the use of monads using the Maybe monad. Let's assume you have the following function.

wrap :: Maybe x -> (x -> y) -> Maybe y
wrap Nothing  f = Nothing
wrap (Just x) f = Just (f x)

now you can call wrap (Just 4) (5+) which will return Just 9.

The idea of the IO-monad is that you can use functions like (+5) on the internal type. The monad will assure that the functions will be called in serial, because every function is chained with the wrapping IO-monad.

2
ответ дан 30 November 2019 в 10:49
поделиться

Единственный полностью чистый функциональный язык, о котором я знаю, - это система шаблонов в C ++. Haskell занимает второе место, делая явными императивные части программы.

В Haskell программа имеет изменяемое состояние, а функции (почти всегда) - нет. Вы сохраняете чистотой около 99% программы, и только та часть, которая взаимодействует с внешним миром, является нечистой. Поэтому, когда вы тестируете функцию, вы знаете, что побочных эффектов нет. Чистое ядро ​​с нечистой оболочкой.

2
ответ дан 30 November 2019 в 10:49
поделиться

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

И это помогло мне лучше писать таблицы стилей XSL.

0
ответ дан 30 November 2019 в 10:49
поделиться

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

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

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

Haskell идет в дальнейшем. Каждая часть программы Haskell чиста (по крайней мере, в отсутствие таких ошибок, как "unsafePerformIO"). Все функции, которые вы пишете на Haskell, являются чистыми.

Побочные эффекты вводятся через монады. Их можно использовать, чтобы ввести своего рода разделение «список покупок - покупатель». По сути, ваша программа составляет список покупок (который представляет собой просто данные, которыми можно манипулировать в чистом виде), в то время как среда выполнения языка интерпретирует список покупок и выполняет эффективные покупки. Весь ваш код чист и удобен для эквациональных рассуждений и тому подобного, тогда как нечистый код предоставляется авторами компилятора.

в то время как языковая среда интерпретирует список покупок и делает эффективные покупки. Весь ваш код чист и удобен для эквациональных рассуждений и тому подобного, тогда как нечистый код предоставляется авторами компилятора.

в то время как языковая среда интерпретирует список покупок и делает эффективные покупки. Весь ваш код чист и удобен для эквациональных рассуждений и тому подобного, тогда как нечистый код предоставляется составителями компилятора.

1
ответ дан 30 November 2019 в 10:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: