Помните, что ОО-метод, вызывающий † , является не чем иным, как синтаксическим сахаром для предоставления дополнительного this
/ self
аргумента функции:
-- OO ┃ functional/procedural
Client c = ...; │ c = ... :: Client
... │ ...
main() {print(c.getFoo());} │ main = print(getFoo c)
Таким образом, вполне возможно и часто полезно идти этим путем как на процедурном языке, таком как C, так и на языке FP.
data Client {
url :: String
, ...
}
getFoo :: Client -> String
getFoo (Client{url = u}) = ...
Да, это требует от вас явной передачи объекта Client
, но это не обязательно плохо - при условии, что вы правильно различаете типы, может быть совершенно очевидно, что нужно передать как аргумент чего функция, и этот подход на самом деле масштабируется лучше, чем методы OO, потому что вы можете иметь несколько объектов в качестве аргументов, и каждая функция может принимать только те, которые ей нужны.
Конечно, есть ситуация, когда у вас есть целый набор функций, которым всем нужен один и тот же объект, и вы хотели бы, чтобы это происходило под капотом без явной передачи его везде. Это можно сделать, скрыв его в типе result .
type Reader c r = c -> r
getFoo :: Reader Client String
getBar :: Reader Client Int
getBaz :: Reader Client Double
Эта читалка монады может использоваться со стандартными монадными комбинаторами:
quun = (`runReader`c) $ do
foo <- getFoo -- `c` argument implicitly passed
bar <- getBar
baz <- getBaz
return (calcQuun foo bar (2*baz))
Этот подход особенно полезен, если у вас также есть мутация в ваших методах, как это обычно происходит в ОО. С явной передачей это становится очень громоздким, так как вам нужно работать с обновленными копиями и быть осторожным, чтобы передавать правильную версию каждой функции. С монадой это обрабатывается автоматически, как если бы это была настоящая мутация.
† Я не обращаю внимания на наследство здесь. Если вы вызываете метод через указатель суперкласса, есть дополнительный поиск в vtable, но он может быть смоделирован как просто другое поле в типе записи, которое сообщает вам, к какому подклассу принадлежит этот объект.