: k e y 1 5 , : k e y 2 n i l } [ 1 2 3 4 " f i v e " ] [ 1 [ 2 ] # { 3 } { 4 4 } ( c o n s t a n t l y 5 ) ] = > ( r a n g e 1 0 ) ( 0 1 2 3 4 5 6 7 8 9 ) = > ( t a k e 1 1 ( r a n g e ) ) ( 0 1 2 3 4 5 6 7 8 9 1 0 ) = > ( l a s t ( r a n g e ) ) ; ; H o p e y o u d o n ' t m i n d w a i t i n g a l o n g t i m e . DATA
l o n s a r e c o m m e n t s , c o m m a s a r e i g n o r e d , ; ; c h e c k o u t t h i s w e i r d h a s h - m a p { : a - k e y w o r d 5 , " a s t r i n g k e y " " a s t r i n g v a l u e " , [ " a " : v e c t o r " a c t i n g " : a s [ : a : c o m p o u n d ] " k e y " ] ( f n [ ] " a n o - a r g f u n c t i o n t h a t r e t u r n s t h i s m u l t i - l i n e s t r i n g , t h e f u n c t i o n i t s e l f i s t h e v a l u e " ) , + ' ( f u n c t i o n s c a n b e k e y s t o o , a n d w h e n y o u q u o t e s y m b o l s , y o u j u s t h a v e s y m b o l s , n o t w h a t t h e y r e p r e s e n t ) } { : a - k e y w o r d 5 , " a s t r i n g k e y " " a s t r i n g v a l u e " , [ " a " : v e c t o r " a c t i n g " : a s [ : a : c o m p o u n d ] " k e y " ] # < u s e r $ e v a l 3 3 1 $ f n _ _ 3 3 2 u s e r $ e v a l 3 3 1 $ f n _ _ 3 3 2 @ a 5 8 5 e f > , # < c o r e $ _ P L U S _ c l o j u r e . c o r e $ _ P L U S _ @ 2 0 a 1 2 d 8 f > ( f u n c t i o n s c a n b e k e y s t o o a n d w h e n y o u q u o t e s y m b o l s y o u j u s t h a v e s y m b o l s n o t w h a t t h e y r e p r e s e n t ) } EVERYTHING IS DATA
also a 'value' 2. Values have true equality 3. Values Never Change (Immutability) 4. Without immutability, objects are just buckets in memory ...have you ever trusted a bucket with no values?
code and rest assured that other parts of my program can't change the data that I'm working on. Q: But I thought every program is simply a short-lived http request handler that talks to a database? We just throw the program state out after every request! A: Well, that's one way to do it.
Node.js assumes threaded programming is hard, and throws out the baby with the bath-water Threaded programming is hard without real 'Data' or 'Values' Composition of any sort is simpler with data
work, storing the last value returned. ( d e f n i n c - l a s t [ v a l ] ( c o n j v a l ( i n c ( l a s t v a l ) ) ) ) ; ; W e m a k e a s e q u e n c e o f 1 0 i n c - l a s t t a s k s , ; ; t h e n f o l l o w - u p w i t h a ' p r i n t l n ' t a s k ( d e f t a s k s ( c o n c a t ( r e p e a t 1 0 i n c - l a s t ) [ ( f n [ v a l ] ( p r i n t l n v a l ) v a l ) ] ) )
f w i t h a v a l u e o f [ 0 ] ( l e t [ a ( a g e n t [ 0 ] ) ] ( d o s e q [ t t a s k s ] ( s e n d a t ) ) ) ; ; p r i n t s : [ 0 1 2 3 4 5 6 7 8 9 1 0 ] Agents are not values, they are mutable references with asynchronous semantics Clojure has other mutable references types, acting as 'containers' for values, for various use cases. Nothing prevents you from making your own.
u r e ( d o - a - b u n c h - o f - s t u f f ) ) ] ; ; i n a n o t h e r t h r e a d ( d o - s t u f f - i n - t h i s - t h r e a d ) ; ; r e t u r n t h e v a l u e i n f , b l o c k i n g i f i t ' s n o t f i n i s h e d ( d e r e f f ) ) MORE! Basically, Clojure promotes your ability to do whatever you want, by simplifying things to their bare essence.
Systems 2. Change our minds 3. Re-use components in different contexts, processes, servers, etc.. Data/Values give us the ability to decouple things easily
a d - s t r i n g " ( + 1 2 ) " ) ) ; ; c l o j u r e . l a n g . P e r s i s t e n t L i s t ( m a p c l a s s ( r e a d - s t r i n g " ( + 1 2 ) " ) ) ; ; ( c l o j u r e . l a n g . S y m b o l j a v a . l a n g . L o n g j a v a . l a n g . L o n g ) R-E-P-L 1. Read: (read-string "(+ 1 2)") => '(+ 1 2) 2. Eval: (eval '(+ 1 2)) => 3 3. What if there's something in the middle?
o n l y - e v e n ! [ v a l ] ( i f ( a n d ( i n t e g e r ? v a l ) ( o d d ? v a l ) ) ( i n c v a l ) v a l ) ) ( m a p o n l y - e v e n ! ( r e a d - s t r i n g " ( + 1 2 ) " ) ) ; ; ' ( + 2 2 ) ( e v a l ( m a p o n l y - e v e n ! ( r e a d - s t r i n g " ( + 1 2 ) " ) ) ) ; ; 4
write that fluent interface code at all? ( u s e ' c l o j u r e . s t r i n g ) ; ; T h e s e a r e e q u i v a l e n t ( m a p t r i m ( s p l i t ( u p p e r - c a s e " h o l a , w o r l d " ) # " , " ) ) ; ; ( " H O L A " " W O R L D " ) ( - > " h o l a , w o r l d " u p p e r - c a s e ( s p l i t # " , " ) ( - > > ( m a p t r i m ) ) ) ; ; ( " H O L A " " W O R L D " )
filtering, etc. ( - > > ( r a n g e ) ( f i l t e r e v e n ? ) ( m a p ( p a r t i a l * 2 ) ) ( t a k e 1 0 ) ( i n t o [ ] ) ) ; ; [ 0 4 8 1 2 1 6 2 0 2 4 2 8 3 2 3 6 ] ; ; v e r s u s ( i n t o [ ] ( t a k e 1 0 ( m a p ( p a r t i a l * 2 ) ( f i l t e r e v e n ? ( r a n g e ) ) ) ) ) 1. I find the flat one easier to think about. 2. Semantically equivalent. 3. No burden on implementing code. Functions don't care about how they're used. Giving the user choices is more effective with more powerful languages. Leads to simple, composable libraries.
m a c r o l a z y - s e q " T a k e s a b o d y o f e x p r e s s i o n s t h a t r e t u r n s a n I S e q o r n i l , a n d y i e l d s a S e q a b l e o b j e c t t h a t w i l l i n v o k e t h e b o d y o n l y t h e f i r s t t i m e s e q i s c a l l e d , a n d w i l l c a c h e t h e r e s u l t a n d r e t u r n i t o n a l l s u b s e q u e n t s e q c a l l s . S e e a l s o - r e a l i z e d ? " { : a d d e d " 1 . 0 " } [ & b o d y ] ( l i s t ' n e w ' c l o j u r e . l a n g . L a z y S e q ( l i s t * ' ^ { : o n c e t r u e } f n * [ ] b o d y ) ) ) ; ; s i m p l y r e t u r n s a l i s t , a l l o c a t e s a J a v a o b j e c t ( L a z y S e q ) a n d w r a p s ; ; y o u r e x p r e s s i o n s i n a f u n c t i o n ( m a c r o e x p a n d - 1 ' ( l a z y - s e q A N Y T H I N G 1 A N Y T H I N G 2 ) ) ; ; ' ( n e w c l o j u r e . l a n g . L a z y S e q ( f n * [ ] A N Y T H I N G 1 A N Y T H I N G 2 ) ) MACROS
mutable variables ( d e f n s q u a r e - w a v e " t i s t h e p e r i o d f o r a h a l f - c y c l e " [ t ] ( l e t f n [ ( o s c [ c u r - v a l u e s o - f a r ] ( l e t [ s o - f a r ( m o d s o - f a r t ) n e x t - v a l ( i f ( z e r o ? s o - f a r ) ( - c u r - v a l u e ) c u r - v a l u e ) ] ( c o n s n e x t - v a l ( l a z y - s e q ( o s c n e x t - v a l ( i n c s o - f a r ) ) ) ) ) ) ] ( o s c 1 0 ) ) ) ( t a k e 1 0 ( s q u a r e - w a v e 3 ) ) ; ; ( - 1 - 1 - 1 1 1 1 - 1 - 1 - 1 1 )