История изменений
Исправление quasimoto, (текущая версия) :
Это же неэквивалентный код. Оригинал тут намного лучше.
Он эквивалентный. С той поправкой, что оригинал хуже — откуда обобщённый код знает про какого-то user, user-name (может я хочу не по name в таблицу пушить а по user-id?) и зачем он разбивает целое на этот user-name и хвост user-data? Пусть общаются через структуру, то есть
(defun receive-users-from-etc-passwd (user-receiver)
...
(funcall user-receiver (make-user login uid gid name home shell)...
;; ^ это
(defun synchronize-from-etc-passwd-to-hash-db (key)
(synchronize ...
;; было:
(lambda (user-name &rest user-data)
(let ((new-user (make-user)))
(mapc (lambda (slot value) (setf (slot-value new-user slot) value))
'(login uid gid name home shell)
(cons user-name user-data))
(setf (gethash user-name *db*) new-user)))))
;; стало:
#'(lambda (user) (setf (gethash (funcall key user) *db*) user)...
Это проще, короче, можно выбрать любой key, эффективнее — структура всё равно формируется, поэтому лучше сделать это сразу и просто передавать через funcall одну ссылку на неё вместо передачи 100500 ссылок на разные составляющие да ещё и через apply (который медленнее funcall).
А вот это:
syn f g h = f $ g <*> h
или
syn f g h = f $ flip g =<< h
в случае монады (a -> _) это
syn f g h = f (\x -> g x (h x))
то есть эквивалентно
(defun syn (f g h)
(funcall f (lambda (x) (funcall g x (funcall h x)))))
некий фильтр g смотрит на x и решает передавать его действию h или нет. То как это решается тоже отдано клиентскому коду, это позволяет написать вещь вроде
synBinary path = syn (fromBinary path) (flip const) evaluate
чего не получится с unless. Для эквивалентности по части unless (unlessM — не макрос но ленивая функция, так что всё ок):
syn' f g h = syn f (unlessM . g) h
-- = f $ unlessM . g <*> h
то есть
(defun syn (f g h)
(funcall f (lambda (x) (unless (funcall g x) (funcall h x)))))
(хотя тут уже макрос) и тогда
synBinaryListToHT key path ht = syn' (fromBinaryList path)
(\x -> isJust <$> HT.lookup ht (key x)) (\x -> HT.insert ht (key x) x)
будет без unlessM.
Исходная версия quasimoto, :
Это же неэквивалентный код. Оригинал тут намного лучше.
Он эквивалентный. С той поправкой, что оригинал хуже — откуда обобщённый код знает про какого-то user, user-name (может я хочу не по name в таблицу пушить а по user-id?) и зачем он разбивает целое на этот user-name и хвост user-data? Пусть общаются через структуру, то есть
(defun receive-users-from-etc-passwd (user-receiver)
...
(funcall user-receiver (make-user login uid gid name home shell)...
;; ^ это
(defun synchronize-from-etc-passwd-to-hash-db (key)
(synchronize ...
;; было:
(lambda (user-name &rest user-data)
(let ((new-user (make-user)))
(mapc (lambda (slot value) (setf (slot-value new-user slot) value))
'(login uid gid name home shell)
(cons user-name user-data))
(setf (gethash user-name *db*) new-user)))))
;; стало:
#'(lambda (user) (setf (gethash (key user) *db*) user)...
Это проще, короче, можно выбрать любой key, эффективнее — структура всё равно формируется, поэтому лучше сделать это сразу и просто передавать через funcall одну ссылку на неё вместо передачи 100500 ссылок на разные составляющие да ещё и через apply (который медленнее funcall).
А вот это:
syn f g h = f $ g <*> h
или
syn f g h = f $ flip g =<< h
в случае монады (a -> _) это
syn f g h = f (\x -> g x (h x))
то есть эквивалентно
(defun syn (f g h)
(funcall f (lambda (x) (funcall g x (funcall h x)))))
некий фильтр g смотрит на x и решает передавать его действию h или нет. То как это решается тоже отдано клиентскому коду, это позволяет написать вещь вроде
synBinary path = syn (fromBinary path) (flip const) evaluate
чего не получится с unless. Для эквивалентности по части unless (unlessM — не макрос но ленивая функция, так что всё ок):
syn' f g h = syn f (unlessM . g) h
-- = f $ unlessM . g <*> h
то есть
(defun syn (f g h)
(funcall f (lambda (x) (unless (funcall g x) (funcall h x)))))
(хотя тут уже макрос) и тогда
synBinaryListToHT key path ht = syn' (fromBinaryList path)
(\x -> isJust <$> HT.lookup ht (key x)) (\x -> HT.insert ht (key x) x)
будет без unlessM.