Замена Clojure для ADT и сопоставления с образцом?
Всякий раз, когда в Haskell нам нужен какой-то вариант типа данных, мы будем использовать ADT в сочетании с сопоставлением с шаблоном. Что люди Clojure используют для таких случаев?
4 ответа
Ну, на самом деле есть несколько библиотек сопоставления с образцом, написанных для Clojure. Макросы Clojure делают подобные вещи возможными. Matchure является одним из самых последних. Есть еще кое-что для ADT в contrib.
Не обращая внимания на эти вещи, самое близкое, что у нас есть к ADT Haskell в ядре Clojure, - это новые записи и типы данных в Clojure 1.2. Но если вам не нужны преимущества, которые дает использование записи или типа данных, вы обычно просто используете карту. Clojure - это динамический язык, поэтому вы не получите статическую проверку типов, если в любом случае используете запись и тому подобное.
Clojure имеет "деструктуризацию", которая напоминает сопоставление с образцом, и часто используется в идиоматических Clojure. Смотрите это и это. Первый действительно ваш ответ здесь, на SO.;п
Это немного зависит от того, что вы пытаетесь сделать. Но, принимая во внимание общий случай, когда требуется полиморфное поведение на основе типа данных, протоколы часто являются хорошим подходом:
(defprotocol Fooable
(foo [x]))
(defrecord AType [avalue]
Fooable
(foo [x]
(println (str "A value: " (:avalue x)))))
(defrecord BType [avalue]
Fooable
(foo [x]
(println (str "B value: " (:bvalue x)))))
(foo (AType. "AAAAAA"))
=> A value: AAAAAA
(foo (BType. "BBBBBB"))
=> B value: BBBBBB
В этом контексте протокол эффективно определяет набор операций, которые вы хотите над своим ADT, а записи определяют возможные значения ADT, а также полиморфное поведение для функций протокола.
Посмотрите на библиотеку matchure - она должна быть включена в clojure-contrib в ближайшее время
Мне очень нравится yap как библиотека для сопоставления с образцом.
Наличие как ключевых слов, так и символов делает реализацию варианта достаточно простой в дополнение к библиотеке сопоставления с образцом.
Можно использовать мультиметоды и макросы.
Один из примеров можно найти ниже.
Итак, как они выглядят в Clojure?
Синтаксис, который будет использовать эта реализация ADT, будет выглядеть следующим образом:
(defadt Tree (Empty) (Leaf value) (Node left right))
Этот синтаксис невероятно похож на код Haskell. Мы также увидим, что мы можем определить функцию глубины, описанную выше, следующим образом:
(defmulti depth adt-type) (defmethod depth Empty [_] 0) (defmethod depth Leaf [_] 1) (defmethod depth Node [node] (+ 1 (max (depth (node :left)) (depth (node :right))))) (defmethod depth :default [_] 0)
Источник: http://gizmo385.github.io/clojure/programming/2015/08/11/adts-in-clojure.html