LINUX.ORG.RU

История изменений

Исправление 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.