开发者

Clojure's substitute for Haskell's ADTs and pattern matching?

开发者 https://www.devze.com 2023-01-12 09:25 出处:网络
Whenever in Haskell we need some variant data type, we would use ADTs开发者_JAVA技巧 in conjunction with pattern matching. What do Clojure folks use for such use cases?Well, there are actually some pa

Whenever in Haskell we need some variant data type, we would use ADTs开发者_JAVA技巧 in conjunction with pattern matching. What do Clojure folks use for such use cases?


Well, there are actually some pattern matching libraries written for Clojure. Clojure's macros make this sort of thing possible. Matchure is one of the most recent. There are even some stuff for ADTs in contrib.

Disregarding that stuff, the closest thing we have to Haskell's ADTs in core Clojure is the new records and datatypes in Clojure 1.2. But, unless you need the benefits that come from using a record or datatype, you'll usually just use a map. Clojure is a dynamic language, so you wont get static type checking if you use a record and such anyway.

Clojure has "destructuring" which is reminiscent of pattern matching, and is used a lot in idiomatic Clojure. See this and this. The former is an answer by yours truly here on SO. ;p


It depends a bit on what you are trying to do. But assuming the common case of wanting polymorphic behaviour based on data type, protocols are often a good approach:

(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

In this context, the protocol effectively defines the set of operations you want on your ADT, and the records define the possible values of the ADT as well as the polymorphic behaviour for the protocol functions.


Look to matchure library - it should be included in clojure-contrib in near time


I like yap very much as a pattern matching library.

The fact to have both keywords and symbols makes implementing variant quite easy on top of a pattern matching library.


It's possible to use multimethods and macros.

One example can be found below.

So how do they look in Clojure?

The syntax that this ADT implementation will use will look like this:

(defadt Tree
 (Empty)
 (Leaf value)
 (Node left right))

This syntax is incredibly similar to the Haskell code. We will also see that we can define the depth function described above like so:

(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)

Source: http://gizmo385.github.io/clojure/programming/2015/08/11/adts-in-clojure.html

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号