Шаг 113.
Основы языка Haskell.
Потенциально бесконечные списки. Моделирование "ленивых" вычислений

    На этом шаге мы рассмотрим процесс моделирования таких вычислений.

Соглашение (об обозначениях).
Неопределённое значение (в теоретическом программировании) обозначается (читается: "основание").
Определение.
  • (1) Говорят, что функция является строгой по аргументу, если для вычисления её значения требуется обязательное вычисление значения этого аргумента.
  • (2) Строгой функцией называется функция, строгая по всем аргументам.
  • (3) Строгой функцией (в функциональном программировании) называется функция  f, для которой
      f(⊥) = ⊥
    


   Замечание. В языке программирования С операции && и || являются строгими по первому аргументу и нестрогими по второму аргументу.

    Библиотечные функции C являются строгими функциями.

    Для простой демонстрации "ленивости" языка Haskell воспользуемся функциями, позволяющими моделировать неопределённое значение.

    Неопределённое значение (в языке Haskell) моделируется с помощью функций

   error и undefined,
имеющих следующие сигнатуры типов:
   Prelude>: t error       Prelude> :t undefined
   error :: String -> a    undefined :: a

    Например:

   Prelude> "123"++error "1"
   "123
   Program execution error: 1


    Примеры демонстрации "ленивых" вычислений в Haskell.
   1. Prelude> head ['a',error "123"]
      'a' :: Char                            => head('a',⊥)='a'

      Prelude> head ['a',undefined]
      'a' :: Char                            => head('a',⊥)='a'

      Prelude> (\ x _ -> x) 1 (error "123")
      1 :: Integer                           => (\ x _ -> x)(1,⊥)=1
Другими словами, если нет необходимости в вычислении значения второго элемента списка, то он и не будет вычисляться.
   2. Prelude> tail ['a',error "123"]
      "
      Program execution error: 123           => tail('a',⊥)=⊥

      Prelude> tail ['a',undefined]
      "
      Program execution error: {undefined}   => tail('a',⊥)=⊥

      Prelude> tail (tail ['a',error "123"])
      "" :: [Char]                           => tail(tail('a',⊥))=""

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

    Таким образом, язык Haskell осуществляет вычисления, интерпретируя равенства в большей степени как объявления (или  определения), чем присваивания, встречающиеся в языках императивного программирования.

    Например, интерпретация определения

   x=1/0
как присваивания означает "вычислите 1/0 и сохраните результат в x", а интерпретация как равенство означает "определите x как 1/0", т.е. значение 1/0 будет вычисляться только тогда, когда оно необходимо (только в этот момент возникнет ошибка "Деление на 0"). Само по себе это определение не подразумевает каких-либо вычислений.

    Программирование с использованием присваиваний требует пристального внимания за соблюдением порядка присваиваний: смысл программы зависит от порядка, в котором эти присваивания выполняются.

Определение.
Строгим языком программирования называется язык программирования, в котором все компоненты структур данных вычисляются до их помещения в структуру.

    На следующем шаге мы рассмотрим моделирование строгих вычислений .




Предыдущий шаг Содержание Следующий шаг