File tree Expand file tree Collapse file tree 4 files changed +76
-1
lines changed Expand file tree Collapse file tree 4 files changed +76
-1
lines changed Original file line number Diff line number Diff line change 1
1
# Changelog #
2
2
3
+ ## Version 2.3.2
4
+
5
+ Date: 2018-11-07
6
+
7
+ - Introduce haskell-inspired do-let macro
8
+
3
9
## Version 2.3.1 ##
4
10
5
11
Date: 2018-10-31
Original file line number Diff line number Diff line change 1
- (defproject funcool /cats " 2.3.1 "
1
+ (defproject funcool /cats " 2.3.2 "
2
2
:description " Category Theory abstractions for Clojure"
3
3
:url " https://github.com/funcool/cats"
4
4
:license {:name " BSD (2 Clause)"
Original file line number Diff line number Diff line change 1013
1013
([ctx f tv]
1014
1014
(ctx/with-context ctx
1015
1015
(p/-traverse (p/-get-context tv) f tv))))
1016
+
1017
+ (defmacro do-let
1018
+ " Haskell-inspired monadic do notation
1019
+ it allows one to drop the _ when we don't need the extracted value
1020
+
1021
+ Basically,
1022
+ (do-let
1023
+ a
1024
+ b
1025
+ [c d
1026
+ e f]
1027
+ x
1028
+ y)
1029
+
1030
+ Translates into:
1031
+
1032
+ (mlet
1033
+ [_ a
1034
+ _ b
1035
+ c d
1036
+ e f
1037
+ _ x]
1038
+ y)
1039
+ "
1040
+ [& forms]
1041
+ (assert (not (empty? forms)) " do-let must have at least one argument" )
1042
+ (assert (not (vector? (last forms))) " Last argument of do-let must not be a vector" )
1043
+ (if (= 1 (count forms))
1044
+ `(do (assert (not (satisfies? p/Monad ~(first forms))) " Single argument of do-let must implement Monad protocol" )
1045
+ ~(first forms))
1046
+ `(mlet ~(vec (reduce (fn [acc form]
1047
+ (cond (vector? form) (into acc form)
1048
+ :else (into acc ['_ form])))
1049
+ []
1050
+ (butlast forms)))
1051
+ ~(last forms))))
Original file line number Diff line number Diff line change 298
298
(t/is (= (maybe/just 1 )
299
299
(ctx/with-context maybe/context
300
300
(m/foldm m-div 1 [])))))))
301
+
302
+ (t/deftest do-let-tests
303
+ (t/testing " Support regular let bindings inside do-let"
304
+ (t/is (= (maybe/just 2 )
305
+ (m/do-let [i (maybe/just 1 )
306
+ :let [i (inc i)]]
307
+ (m/return i)))))
308
+
309
+ (t/testing " Support :when guards inside its bindings"
310
+ (t/is (= (maybe/nothing )
311
+ (m/do-let [i (maybe/just 2 )
312
+ :when (> i 2 )]
313
+ (m/return i))))
314
+ (t/is (= [3 4 5 ]
315
+ (m/do-let [i [1 2 3 4 5 ]
316
+ :when (> i 2 )]
317
+ (m/return i)))))
318
+
319
+ (t/testing " Support one single form"
320
+ (t/is (= (maybe/just 2 )
321
+ (m/do-let (maybe/just 2 )))))
322
+
323
+ (t/testing " Support multiple single form"
324
+ (t/is (= (maybe/just 3 )
325
+ (m/do-let (maybe/just 2 )
326
+ (maybe/just 3 )))))
327
+
328
+ (t/testing " Bound variables are always in scope"
329
+ (t/is (= (maybe/just 6 )
330
+ (m/do-let [x (maybe/just 2 )]
331
+ (maybe/just x)
332
+ [y (maybe/just (+ 2 x))]
333
+ (maybe/just (+ 2 y)))))))
You can’t perform that action at this time.
0 commit comments