Як може функціонувати час у функціональному програмуванні?


646

Я мушу визнати, що я мало знаю про функціональне програмування. Я читав про це звідси і там, і так дізнався, що у функціональному програмуванні функція повертає той самий вихід, за той же вхід, незалежно від того, скільки разів функція викликається. Це точно як математична функція, яка оцінює один і той же вихід на те саме значення вхідних параметрів, яке бере участь у вираженні функції.

Наприклад, врахуйте це:

f(x,y) = x*x + y; // It is a mathematical function

Незалежно від того, скільки разів ви використовуєте f(10,4), його значення завжди буде 104. Таким чином, де б ви не писали f(10,4), ви можете замінити його 104, не змінюючи значення цілого виразу. Ця властивість називається референтною прозорістю виразу.

Як говорить Вікіпедія ( посилання ),

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

Чи може функціонал часу (який повертає поточний час) існувати у функціональному програмуванні?

  • Якщо так, то як воно може існувати? Чи не порушує принцип функціонального програмування? Це особливо порушує референтну прозорість, яка є однією з властивостей функціонального програмування (якщо я правильно це розумію).

  • Або якщо ні, то як можна знати поточний час у функціональному програмуванні?


15
Я думаю, що більшість (або всі) функціональні мови не настільки суворі і поєднують функціональне та імперативне програмування. Принаймні, це моє враження від F #.
Алекс F

13
@Adam: Як би абонент в першу чергу дізнався поточний час?
Наваз

29
@Adam: Насправді це є незаконним (як у: неможливо) чисто функціональними мовами.
sepp2k

47
@Adam: Досить. Чиста мова загального призначення, як правило, пропонує певні можливості потрапити у "світовий стан" (тобто такі речі, як поточний час, файли в каталозі тощо), не порушуючи референсної прозорості. У Haskell це монада IO, а в Clean - це світовий тип. Тож у цих мовах функція, яка потребує поточного часу, буде або вважати її аргументом, або потрібно буде повернути дію вводу-виводу замість її фактичного результату (Haskell) або взяти світовий стан як аргумент (Clean).
sepp2k

12
Думаючи про FP, це легко забути: комп’ютер - це великий шматок змінного стану. FP цього не змінює, вона просто приховує.
Даніель

Відповіді:


176

Ще один спосіб пояснити це: жодна функція не може отримати поточний час (оскільки вона постійно змінюється), але дія може отримати поточний час. Скажімо, getClockTimeце константа (або нульова функція, якщо вам подобається), яка представляє дію отримання поточного часу. Ця дія є однаковою щоразу, незалежно від того, коли вона використовується, тому вона є реальною постійною.

Так само, скажімо print, це функція, яка займає деякий час подання та друкує її на консолі. Оскільки виклики функцій не можуть мати побічні ефекти чистою функціональною мовою, ми замість цього уявляємо, що це функція, яка приймає часову позначку і повертає дію друку на консоль. Знову ж таки, це реальна функція, тому що якщо ви надаєте їй одну і ту ж часову позначку, вона буде щоразу повертати ту саму дію друку.

Тепер, як можна надрукувати поточний час на консолі? Ну, ви повинні поєднати дві дії. То як ми можемо це зробити? Ми не можемо просто перейти getClockTimeдо print, так як друк очікує мітку часу, а не дія. Але ми можемо уявити, що існує оператор, >>=який поєднує дві дії, одну, яка отримує часову позначку, і ту, яка приймає одну як аргумент і друкує її. Застосовуючи це до раніше згаданих дій, результатом є ... tadaaa ... нова дія, яка отримує поточний час і друкує його. І це, до речі, саме так робиться в Haskell.

Prelude> System.Time.getClockTime >>= print
Fri Sep  2 01:13:23 東京 (標準時) 2011

Отже, концептуально ви можете переглянути це таким чином: Чиста функціональна програма не виконує жодного вводу-виводу, вона визначає дію , яку потім виконує система виконання. Дія одне і те ж кожен раз, але результат його виконання залежить від обставин , коли воно виконується.

Я не знаю, чи це було ясніше, ніж інші пояснення, але іноді це допомагає мені думати про це таким чином.


33
Це не переконливо для мене. Ви зручно називати getClockTimeдію замість функції. Ну, якщо ви так називаєте, то викликайте кожну дію функції , тоді навіть імперативне програмування стане функціональним програмуванням. Або , може бути, ви хотіли б назвати це Actional programmming.
Наваз

92
@Nawaz: Головне, що тут слід зазначити, це те, що ви не можете виконати дію в межах функції. Ви можете комбінувати дії та функції лише для того, щоб робити нові дії. Єдиний спосіб виконання дії - скласти її у свою mainдію. Це дозволяє відокремити чистий функціональний код від імперативного коду, і це розділення забезпечується системою типів. Трактування дій як об'єктів першого класу також дозволяє вам передавати їх навколо та будувати власні "структури управління".
хаммар

36
Не все в Haskell - це функція - це суцільна нісенітниця. Функція - це те, чий тип містить: ->- ось як стандарт визначає термін, і це дійсно єдине розумне визначення в контексті Haskell. Так - то, тип якого IO Whateverє НЕ функцією.
sepp2k

9
@ sepp2k Отже, myList :: [a -> b] - це функція? ;)
fuz

8
@ThomasEding Я дуже спізнююся на вечірку, але я просто хочу уточнити це: putStrLnце не дія - це функція, яка повертає дію. getLine- змінна, яка містить дію. Дії - це значення, змінні та функції - це "контейнери" / "мітки", які ми надаємо цим діям.
kqr

356

Так і ні.

Різні функціональні мови програмування вирішують їх по-різному.

У Haskell (дуже чистому) все це має відбуватися у тому, що називається Monad I / O - дивіться тут .

Ви можете подумати про це як про отримання іншого вкладу (і виведення) у свою функцію (стан світу) або простіше як про місце, де відбувається "нечистота", як отримання часу, що змінюється.

В інших мовах, таких як F #, просто вбудовано деяку нечистоту, і тому ви можете мати функцію, яка повертає різні значення для одного і того ж вводу - як і звичайні обов'язкові мови.

Як згадував Джеффрі Бурка у своєму коментарі: Ось приємний вступ до монади вводу-виводу прямо з вікі Haskell.


223
Найважливіше, що слід усвідомити про монаду вводу-виводу в Хаскелл, це те, що не просто зламати цю проблему; монади - це загальне рішення проблеми визначення послідовності дій у якомусь контексті. Один з можливих контекстів - це реальний світ, для якого у нас є монада IO. Інший контекст - це атомна транзакція, для якої у нас монада STM. Ще один контекст полягає у здійсненні процедурного алгоритму (наприклад, переміщення Кнута) як чистої функції, для якої у нас монада ST. І ви також можете визначити свої власні монади. Монади - це різновид накладеної крапки з комою.
Пол Джонсон

2
Мені здається корисним не називати такі речі, як отримання поточного часу "функціями", а щось на зразок "процедури" (хоча спірне рішення Haskell є винятком з цього).
сінгполіма

з точки зору Haskell класичні "процедури" (речі, що мають типи типу "... -> ()") є дещо тривіальними, оскільки чиста функція з ... -> () взагалі нічого не може зробити.
Карстен

3
Типовий термін Хаскелла - "дія".
Себастьян Редл

6
"Монади - це своєрідна точка з комою, яку можна перезавантажити". +1
користувач2805751

147

У Хаскеллі використовується конструкція, яка називається монадою для обробки побічних ефектів. В основному монада означає, що ви інкапсулює значення в контейнер і маєте деякі функції для ланцюга функцій від значень до значень всередині контейнера. Якщо наш контейнер має тип:

data IO a = IO (RealWorld -> (a,RealWorld))

ми можемо безпечно реалізовувати дії з виводу. Цей тип означає: Дія типу IO- це функція, яка приймає маркер типу RealWorldі повертає новий маркер разом з результатом.

Ідея цього полягає в тому, що кожна дія IO мутує зовнішній стан, представлене магічним ознакою RealWorld. Використовуючи монади, можна зв'язати кілька функцій, які мутують реальний світ разом. Найважливішою функцією монади є >>=виражене зв’язування :

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

>>=виконує одну дію і функцію, яка приймає результат цієї дії і створює з цього нову дію. Тип повернення - це нова дія. Наприклад, зробимо вигляд, що є функція now :: IO String, яка повертає рядок, що представляє поточний час. Ми можемо зв'язати це з функцією putStrLnдля його роздруківки:

now >>= putStrLn

Або написано в do-нотації, яка більше знайома імперативному програмісту:

do currTime <- now
   putStrLn currTime

Все це чисто, оскільки ми відображаємо мутацію та інформацію про світ зовні RealWorld. Отже щоразу, виконуючи цю дію, ви отримуєте, звичайно, різний вихід, але вхід не той самий: RealWorldмаркер інший.


3
-1: Я незадоволений RealWorldдимовим екраном. І все ж, найголовніше - це те, як цей нібито об'єкт передається ланцюжком. Відсутній фрагмент - там, де він починається, де джерело або з'єднання з реальним світом - він починається з основної функції, яка працює в монаді IO.
u0b34a0f6ae

2
@ kaizer.se Ви можете придумати глобальний RealWorldоб'єкт, який передається в програму при його запуску.
fuz

6
В основному, ваша mainфункція бере RealWorldаргументи. Тільки після страти він переданий.
Луї Васерман

13
Розумієте, причина, по якій вони приховують RealWorldі надають лише хитрі функції, щоб змінити її на кшталт putStrLn, - це те, що якийсь програміст Haskell не змінюється ні RealWorldв одній із своїх програм, так що адреса і дата народження Haskell Curry є такими, що вони стають сусідськими сусідами дорослішання (це може пошкодити континуум часу та просто зашкодити мові програмування Haskell.)
PyRulez

2
RealWorld -> (a, RealWorld) не руйнується як метафора навіть за умови одночасності, якщо ви пам’ятаєте, що реальний світ може змінюватися іншими частинами Всесвіту поза вашою функцією (або вашим поточним процесом) у будь-який час. Так (а) вибирає , предзадано не ламається, і (б) кожен раз , коли значення , яке має , RealWorldяк його типу передається функція, то функція повинна бути повторно оцінена, тому що реальний світ буде змінитися в той же час ( який моделюється так, як пояснив @fuz, повертаючи інше значення "лексеми" кожного разу, коли ми взаємодіємо з реальним світом).
Qqwy

73

Більшість функціональних мов програмування не є чистими, тобто вони дозволяють функціям не залежати лише від їх значень. У цих мовах цілком можливо мати функцію, що повертає поточний час. З мов, якими ви позначили це питання, стосується Scala та F # (а також більшості інших варіантів ML ).

У таких мовах, як Haskell і Clean , які є чистими, ситуація інша. У Haskell поточний час був би доступний не через функцію, а так звану IO-дію, що є способом Haskell інкапсуляції побічних ефектів.

У «Чистому» це буде функцією, але функція сприймає світову цінність як аргумент і повертає свіжу світову цінність (крім поточного часу) як результат. Система типів гарантує, що кожне світове значення може бути використане лише один раз (і кожна функція, яка споживає світову цінність, створює нову). Таким чином, функцію часу потрібно було б викликати з різним аргументом кожен раз, і тому було б дозволено щоразу повертати інший час.


2
Це звучить так, ніби Haskell і Clean роблять різні речі. З того, що я розумію, вони роблять те саме, тільки що Haskell пропонує приємніший синтаксис (?) Для досягнення цього.
Конрад Рудольф

27
@Konrad: Вони роблять те ж саме в тому сенсі, що обидва використовують типи системних функцій для абстрактних побічних ефектів, але це стосується цього. Зауважте, що дуже добре пояснити монаду вводу-виводу з точки зору світового типу, але стандарт Haskell насправді не визначає тип світу, і фактично неможливо отримати значення типу World у Haskell (хоча це дуже можливо і справді необхідно в чистому). Далі Haskell не має унікальності введення в якості системної функції типу, тому, якщо він дозволив вам отримати доступ до світу, він не міг би забезпечити, щоб ви використовували його в чистому вигляді, як це робить Clean.
sepp2k

51

"Поточний час" - це не функція. Це параметр. Якщо ваш код залежить від поточного часу, це означає, що ваш код параметризований часом.


22

Це абсолютно можна зробити чисто функціональним способом. Існує кілька способів зробити це, але найпростішим є отримання функцією часу повертати не тільки час, але і функцію, яку ви повинні зателефонувати, щоб отримати наступне вимірювання часу .

У C # ви можете реалізувати це так:

// Exposes mutable time as immutable time (poorly, to illustrate by example)
// Although the insides are mutable, the exposed surface is immutable.
public class ClockStamp {
    public static readonly ClockStamp ProgramStartTime = new ClockStamp();
    public readonly DateTime Time;
    private ClockStamp _next;

    private ClockStamp() {
        this.Time = DateTime.Now;
    }
    public ClockStamp NextMeasurement() {
        if (this._next == null) this._next = new ClockStamp();
        return this._next;
    }
}

(Майте на увазі, що цей приклад мав бути простим, а не практичним. Зокрема, вузли списку не можуть бути зібрані сміття, оскільки вони укорінені ProgramStartTime.)

Цей клас "ClockStamp" діє як незмінний пов'язаний список, але насправді вузли створюються на вимогу, щоб вони могли містити "поточний" час. Будь-яка функція, яка хоче виміряти час, повинна мати параметр «clockStamp», а також повинна повертати своє останнє вимірювання часу в результаті (щоб абонент не бачив старих вимірів), наприклад:

// Immutable. A result accompanied by a clockstamp
public struct TimeStampedValue<T> {
    public readonly ClockStamp Time;
    public readonly T Value;
    public TimeStampedValue(ClockStamp time, T value) {
        this.Time = time;
        this.Value = value;
    }
}

// Times an empty loop.
public static TimeStampedValue<TimeSpan> TimeALoop(ClockStamp lastMeasurement) {
    var start = lastMeasurement.NextMeasurement();
    for (var i = 0; i < 10000000; i++) {
    }
    var end = start.NextMeasurement();
    var duration = end.Time - start.Time;
    return new TimeStampedValue<TimeSpan>(end, duration);
}

public static void Main(String[] args) {
    var clock = ClockStamp.ProgramStartTime;
    var r = TimeALoop(clock);
    var duration = r.Value; //the result
    clock = r.Time; //must now use returned clock, to avoid seeing old measurements
}

Звичайно, провести це останнє вимірювання в, і в, і в, і в, трохи незручно. Існує багато способів приховати котельну плиту, особливо на рівні мовної розробки. Я думаю, що Haskell використовує подібний трюк, а потім приховує потворні частини, використовуючи монади.


Цікаво, але те, що i++в циклі for не референтно прозоре;)
snim2

@ snim2 Я не ідеальний. : P Будьте розраховані в тому, що брудна змінність не впливає на референтну прозорість результату. Якщо ви пропустите той самий "lastMeasurement" двічі, ви отримаєте чергове наступне вимірювання і повернете той же результат.
Крейг Гідні

@Strilanc Дякую за це. Я думаю, що в імперативному кодексі, тому цікаво бачити, як це пояснюються функціональні концепції. Тоді я можу уявити мову, де це природне та синтаксично чистіше.
ВВ.

Насправді ви могли також пройти монаду в C #, тим самим уникаючи явного проходження часових позначок. Вам потрібно щось подібне struct TimeKleisli<Arg, Res> { private delegate Res(TimeStampedValue<Arg>); }. Але код з цим все-таки не виглядатиме так добре, як Haskell із doсинтаксисом.
близько

@leftaroundabout ви можете зробити вигляд, що у вас є монада в C #, реалізуючи функцію bind як метод SelectMany, який називається , що дозволяє синтаксис розуміння запиту. Ти все ще не можеш програмувати поліморфно над монадами, тому все це важкий бій проти системи слабкого типу :(
Сара

16

Я здивований, що жоден з відповідей чи коментарів не згадує вугілля або коіндукцію. Зазвичай про коіндукцію згадують, коли міркують про нескінченну структуру даних, але вона також застосовна до нескінченного потоку спостережень, наприклад, реєстру часу в ЦП. Вугільна модель моделює прихований стан; та моделі коіндукції, що дотримуються цього стану. ( Побудова нормальних моделей індукції стан.)

Це гаряча тема в Реактивне функціональне програмування. Якщо вас цікавлять подібні речі, прочитайте це: http://digitalcommons.ohsu.edu/csetech/91/ (28 pp.)


3
І як це пов’язано з цим питанням?
Наваз

5
Ваше запитання стосувалося моделювання поведінки, залежно від часу, чисто функціональним способом, наприклад, функцією, яка повертає поточний системний годинник. Ви можете або вивести щось еквівалентне монаді IO через усі функції та дерево їх залежності, щоб отримати доступ до цього стану; або ви можете моделювати стан, визначивши правила спостереження, а не конструктивні правила. Ось чому індуктивно моделювати складний стан у функціональному програмуванні здається таким неприродним, оскільки прихований стан справді є коіндуктивною властивістю.
Джеффрі Агілера

Чудове джерело! Чи є щось нещодавніше? Спільнота JS як і раніше бореться з абстракціями потокових даних.
Дмитро Зайцев

12

Так, для чистої функції можна повернути час, якщо цей час заданий як параметр. Різні аргументи часу, різний часовий результат. Потім сформуйте й інші функції часу та поєднайте їх з простим словником функцій (-of-time) -трансформації (вищого порядку). Оскільки підхід без стану, час тут може бути безперервним (незалежним від роздільної здатності), а не дискретним, що значно підвищує модульність . Ця інтуїція є основою функціонального реактивного програмування (FRP).


11

Так! Ви праві! Тепер () або CurrentTime () або будь-який метод підпису такого аромату жодним чином не демонструє референсної прозорості. Але за інструкцією до компілятора вона параметризується системним входом тактової частоти.

За результатами, Now () може виглядати як такий, що не дотримується еталонної прозорості. Але реальна поведінка системного годинника та функції, що знаходиться на ньому, дотримується референтної прозорості.


11

Так, функція отримання часу може існувати у функціональному програмуванні, використовуючи дещо змінену версію функціонального програмування, відому як нечисте функціональне програмування (за замовчуванням або головна - це чисте функціональне програмування).

У разі отримання часу (або читання файлу, або запуску ракети) код повинен взаємодіяти із зовнішнім світом, щоб виконати роботу, і цей зовнішній світ не базується на чистих основах функціонального програмування. Щоб чистий функціональний світ програмування міг взаємодіяти з цим нечистим зовнішнім світом, люди запровадили нечисте функціональне програмування. Зрештою, програмне забезпечення, яке не взаємодіє із зовнішнім світом, не є корисним, крім того, як робити деякі математичні обчислення.

Мало функціональних мов програмування має вбудовану в них функцію домішок таким чином, що не просто відокремити, який код нечистий, а чистий (наприклад, F # тощо), а деякі функціональні мови програмування переконайтеся, що, коли ви робите якісь нечисті речі цей код явно виділяється порівняно з чистим кодом, як Haskell.

Ще один цікавий спосіб це побачити в тому, що функція отримання часу в функціональному програмуванні займе "світовий" об'єкт, який має поточний стан світу, наприклад, час, кількість людей, що живуть у світі, і т. Д. Потім отримує час, з якого світу об'єкт буде завжди чистим, тобто ви проходите в одній світовій державі, ви завжди отримаєте той самий час.


1
"Зрештою, програмне забезпечення, яке не взаємодіє із зовнішнім світом, не є корисним, крім того, як робити деякі математичні обчислення." Наскільки я розумію, навіть у цьому випадку введення в обчислення було б жорстко закодованим у програмі, також не дуже корисним. Як тільки ви хочете прочитати вхідні дані для математичного обчислення з файлу чи терміналу, вам потрібен нечистий код.
Джорджіо

1
@Ankur: Це та сама точна річ. Якщо програма взаємодіє з чимось іншим, ніж просто з собою (наприклад, світом через клавіатуру, так би мовити), це все ще нечисто.
особистість

1
@Ankur: Так, я думаю, ти маєш рацію! Незважаючи на те, що передавати великі вхідні дані в командному рядку може не дуже практично, це може бути чистим способом.
Джорджіо

2
Наявність "світового об'єкта", включаючи кількість людей, що живуть у світі, піднімає виконавчий комп'ютер майже до всезнаючого рівня. Я думаю, що нормальний випадок полягає в тому, що він включає в себе такі речі, як кількість файлів на вашому HD і те, що домашня директорія поточного користувача.
ziggystar

4
@ziggystar - "світовий об'єкт" насправді нічого не включає - це просто проксі для зміни стану світу поза програмою. Єдина його мета - явно позначити стан, що змінюється, таким чином, щоб система типів могла його ідентифікувати.
Kris Nuttycombe

7

Ваше запитання пов'язує два суміжні заходи комп'ютерної мови: функціональний / імперативний та чистий / нечистий.

Функціональна мова визначає зв'язки між входами та виходами функцій, а імперативна мова описує конкретні операції в певному порядку для виконання.

Чиста мова не створює і не залежить від побічних ефектів, а нечиста мова використовує їх протягом усього часу.

Стовідсоткові чисті програми в основному марні. Вони можуть виконати цікавий розрахунок, але оскільки вони не можуть мати побічні ефекти, вони не мають вводу та виводу, тому ви ніколи не дізнаєтесь, що вони обчислили.

Щоб бути корисною, програма повинна бути як мінімум нечистою. Один із способів зробити чисту програму корисною - помістити її всередину тонкої нечистої обгортки. Як і ця неперевірена програма Haskell:

-- this is a pure function, written in functional style.
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

-- This is an impure wrapper around the pure function, written in imperative style
-- It depends on inputs and produces outputs.
main = do
    putStrLn "Please enter the input parameter"
    inputStr <- readLine
    putStrLn "Starting time:"
    getCurrentTime >>= print
    let inputInt = read inputStr    -- this line is pure
    let result = fib inputInt       -- this is also pure
    putStrLn "Result:"
    print result
    putStrLn "Ending time:"
    getCurrentTime >>= print

4
Було б корисно, якщо ви могли б вирішити конкретну проблему отримання часу і пояснити трохи про те, наскільки ми вважаємо IOцінності та результати чистими.
AndrewC

Насправді навіть 100% чисті програми нагрівають процесор, що є побічним ефектом.
Йорг W Міттаг

3

Ви обговорюєте дуже важливий предмет у функціональному програмуванні, тобто виконуючи введення-виведення. Шлях чистих мов проходить через це за допомогою вбудованих мов, що стосуються домену, наприклад, підмовою, завданням якої є кодування дій , що може мати результати.

Наприклад, час виконання Haskell очікує, що я визначу дію під назвою main що складається з усіх дій, що складають мою програму. Потім виконується ця дія. Більшість часу він виконує чистий код. Час від часу виконання буде використовувати обчислені дані для виконання вводу-виводу та повернення даних назад у чистий код.

Ви можете поскаржитися, що це звучить як обман, і певним чином це так: визначаючи дії та очікуючи виконання їх виконання, програміст може зробити все, що може зробити звичайна програма. Але система сильного типу Haskell створює сильний бар'єр між чистими та "нечистими" частинами програми: ви не можете просто додати, скажімо, дві секунди до поточного часу процесора, і роздрукувати його, ви повинні визначити дію, що призводить до поточного Час процесора, і переведіть результат на іншу дію, яка додає дві секунди і друкує результат. Написання занадто великої кількості програми вважається поганим стилем, тому що це важко зробити висновок, які ефекти викликаються, порівняно з типами Haskell, які говорять нам про все, що ми можемо знати, що таке значення.

Приклад: clock_t c = time(NULL); printf("%d\n", c + 2);у С, порівняно main = getCPUTime >>= \c -> print (c + 2*1000*1000*1000*1000)з Хаскелом. Оператор >>=використовується для складання дій, передаючи результат першої функції функції, що призводить до другої дії. Це виглядає досить притаманно, компілятори Haskell підтримують синтаксичний цукор, що дозволяє нам записати останній код наступним чином:

type Clock = Integer -- To make it more similar to the C code

-- An action that returns nothing, but might do something
main :: IO ()
main = do
    -- An action that returns an Integer, which we view as CPU Clock values
    c <- getCPUTime :: IO Clock
    -- An action that prints data, but returns nothing
    print (c + 2*1000*1000*1000*1000) :: IO ()

Останнє виглядає досить імперативно, чи не так?


1

Якщо так, то як воно може існувати? Чи не порушує принцип функціонального програмування? Особливо це порушує референтну прозорість

Вона не існує в чисто функціональному сенсі.

Або якщо ні, то як можна знати поточний час у функціональному програмуванні?

Спочатку може бути корисно знати, як час витягується на комп’ютері. По суті, є вбудована схема, яка відслідковує час (саме тому комп'ютеру зазвичай потрібна батарея з невеликим осередком). Тоді може бути якийсь внутрішній процес, який встановлює значення часу в певному регістрі пам'яті. Це по суті зводиться до значення, яке може бути отримано ЦП.


Для Haskell існує концепція "IO action", яка представляє тип, який можна зробити для здійснення певного процесу вводу-виводу. Тож замість посилання на timeзначення ми посилаємось на IO Timeзначення. Все це було б суто функціональним. Ми не посилаємось, timeа щось, що відповідає принципу "прочитати значення регістра часу" .

Коли ми насправді виконуємо програму Haskell, дія IO насправді відбуватиметься.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.