Я действительно почувствовал силу, когда узнал, что функция может быть частью структуры данных. Вот «потребительская монада» (technobabble: бесплатная монада свыше (i ->)
).
data Coro i a
= Return a
| Consume (i -> Coro i a)
Таким образом, Coro
может либо мгновенно дать значение, либо быть другим Coro в зависимости от некоторого ввода. Например, это Coro Int Int
:
Consume $ \x -> Consume $ \y -> Consume $ \z -> Return (x+y+z)
Это потребляет три целочисленных ввода и возвращает их сумму. Вы также можете заставить его вести себя по-разному в зависимости от входных данных:
sumStream :: Coro Int Int
sumStream = Consume (go 0)
where
go accum 0 = Return accum
go accum n = Consume (\x -> go (accum+x) (n-1))
Это потребляет Инт, а затем потребляет столько же Инт, прежде чем получить их сумму. Это можно рассматривать как функцию, которая принимает произвольно много аргументов, построенную без какой-либо языковой магии, только функции более высокого порядка.
Функции в структурах данных - очень мощный инструмент, который не был частью моего словарного запаса до того, как я начал заниматься Haskell.