Ведение журнала из парадигмы функционального программирования

Я предпочитаю как можно точнее придерживаться функциональной парадигмы, стараясь максимально приблизиться к чисто функциональному, когда мой мозг готов принять вызов. По возможности я использую F #. Обычно я застреваю либо на VB.NET, либо на C # (или на VBA, когда мне действительно не везет). Так что мои языки позволяют мне довольно далеко уйти от функционального подхода.

Исторически я игнорировал ведение журнала и общение с пользователем до тех пор, пока не получу результат - просто позвольте пользователю подождать. Сейчас пытаюсь реализовать ведение журнала и / или обновление статус-бара. Это легко, потому что мои языки позволяют мне писать в стандартный вывод, когда я хочу. Но с чисто функциональной точки зрения, как можно допустить утечку информации о том, что происходит внутри его функции, во внешний мир? Является ли ведение журнала или общение с пользователем во время вычислений просто противоречащим чисто функциональному подходу?

Я уверен, что в Haskell можно использовать монаду. А как насчет использования других языков?

Спасибо.


person Jeff Maner    schedule 07.12.2012    source источник
comment
I prefer to stick as closely as possible to the functional paradigm, squeezing as close as I can get to the purely functional when my brain is up for the challenge используйте его, когда это приносит вам пользу. Чистый функциональный код часто может добавить системе случайную сложность.   -  person Lukasz Madon    schedule 08.12.2012
comment
Наверное, это хороший совет ...   -  person Jeff Maner    schedule 11.12.2012


Ответы (2)


Давайте посмотрим на монадическое решение Haskell. Идея ведения журнала заключается в том, что в наших вычислениях есть дополнительный метод, который записывает сообщение где-то «вне». Есть много способов представить такие вычисления, но один из самых общих - создать монаду:

class (Monad m) => MonadWriter w m | m -> w where
    tell   :: w -> m ()

Тип w представляет сообщения, а функция tell - это то, что «отправляет» сообщение в монадическое (полное) вычисление.

Примечания:

  • MonadWriter Haskell на самом деле богаче, он содержит функции, позволяющие проверять и изменять w, но давайте пока оставим это в стороне.
  • Часть | m -> w на самом деле не важна для объяснения, она просто означает, что w исправлено для данного m.

Чаще всего используется реализация Writer, которая представляет собой просто пару. Один его элемент - результат вычислений, а другой - последовательность письменных сообщений. (На самом деле это не совсем последовательность, это более общий моноид, который определяет операции для объединения нескольких сообщений в одно.) Вы можете изучить решение Haskell, посмотрев на Модуль Writer. Однако он написан в более общем плане с использованием WriterT преобразователя монад, поэтому, если вы не фанат монад, его будет довольно трудно прочитать. То же самое можно сделать и на других функциональных языках, например см. этот пример на Scala.

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

{-# LANGUAGE FunctionalDependencies, TypeSynonymInstances, FlexibleInstances #-}

instance MonadWriter String IO where
    tell = putStrLn

Здесь мы говорим, что IO можно использовать как средство ведения журнала, которое записывает Strings в стандартный вывод. (Это просто упрощенный пример, полная реализация, вероятно, будет иметь преобразователь монад, который добавит tell функциональность к любой монаде, основанной на IO.)

person Petr    schedule 08.12.2012
comment
Классы и предметы? Что? Это не парадигма функционального программирования, это просто ООП в ФП. - person Brian Cannard; 24.04.2016
comment
Я не вижу в этом смысла, классы типов в Haskell сильно отличаются от объектно-ориентированных классов. - person Petr; 24.04.2016
comment
Спасибо. Может, я тоже не вижу в этом смысла. В этом ответе нет варианта использования класса. Пожалуйста, сосредоточьтесь на использовании клиентской части логирования вместо библиотеки. Спасибо! - person Brian Cannard; 24.04.2016
comment
Интересно посмотреть, как тип журналирования передается функциям и используется для создания и возврата описаний журналирования. Я имею в виду абсолютно чистую часть кода без каких-либо побочных эффектов. Где результаты должны быть объединены и переданы фактическому исполнителю побочных эффектов регистратора? На высшем / некотором промежуточном уровне, но определенно не внутри функций приложения. Результаты регистрации должны быть только командами для регистратора. Интересно посмотреть, как можно составлять такие результаты и сочетать их с другими функциями. - person Brian Cannard; 24.04.2016

Я новичок в функциональном программировании, но вот попытка на Scala:

object FunctionalLogging {

  type Result = Int

  class ResultWithLogging(val log: List[String], val result: Result) {}

  def functionWithLogging(log: List[String], arg: String): ResultWithLogging = {
    def function(arg: String): Result = arg.length

    new ResultWithLogging(log :+ ("Calling function(" + arg +")"), function(arg))
  }

  val result = functionWithLogging(List(), "Hello world!")

  // -- Pure functional code ends here --
  println("Result = " + result.result)
  println("Log = " + result.log)
}

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

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

Это более прагматичный взгляд: Вход в Scala

Изменить

В этом вопросе говорится о монадах Haskell и вводе-выводе: Какие еще способы обработки состояний можно использовать на чистом функциональном языке, кроме Monads?

person richj    schedule 07.12.2012
comment
Мне здесь нравится твой мыслительный процесс. В моем случае, однако, функция выполнялась довольно долго, и я хотел сообщать о том, как она обрабатывается, а не ждать ее возврата, чтобы сообщить свой журнал. Тем не менее, если на мой вопрос никто не ответит, я, вероятно, отмечу это как ответ, потому что, хотя ответ Haskell отличный, мой вопрос был более конкретно о подходах, отличных от монад. Спасибо! - person Jeff Maner; 11.12.2012