summaryrefslogtreecommitdiffhomepage
path: root/hy.html.markdown
blob: 1287095fbf711061fa14641ab2672b504c419361 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
---
language: hy
filename: learnhy.hy
contributors:
    - ["Abhishek L", "http://twitter.com/abhishekl"]
    - ["Zirak", "http://zirak.me"]
---

Hy is a lisp dialect built on top of python. This is achieved by
converting hy code to python's abstract syntax tree (ast). This allows
hy to call native python code or python to call native hy code as well

This tutorial works for hy ≥ 0.9.12, with some corrections for hy 0.11.

```clojure
;; this gives an gentle introduction to hy for a quick trial head to
;; http://try-hy.appspot.com
;;
; Semicolon comments, like other LISPS

;; s-expression basics
; lisp programs are made of symbolic expressions or sexps which
; resemble
(some-function args)
; now the quintessential hello world
(print "hello world")

;; simple data types
; All simple data types are exactly similar to their python counterparts
; which
42 ; => 42
3.14 ; => 3.14
True ; => True
4+10j ; => (4+10j) a complex number

; lets start with some really simple arithmetic
(+ 4 1) ;=> 5
; the operator is applied to all arguments, like other lisps
(+ 4 1 2 3) ;=> 10
(- 2 1) ;=> 1
(* 4 2) ;=> 8
(/ 4 1) ;=> 4
(% 4 2) ;=> 0 the modulo operator
; power is represented by ** operator like python
(** 3 2) ;=> 9
; nesting forms will do the expected thing
(+ 2 (* 4 2)) ;=> 10
; also logical operators and or not and equal to etc. do as expected
(= 5 4) ;=> False
(not (= 5 4)) ;=> True

;; variables
; variables are set using setv, variable names can use utf-8 except
; for ()[]{}",'`;#|
(setv a 42)
(setv π 3.14159)
(def *foo* 42)
;; other container data types
; strings, lists, tuples & dicts
; these are exactly same as python's container types
"hello world" ;=> "hello world"
; string operations work similar to python
(+ "hello " "world") ;=> "hello world"
; lists are created using [], indexing starts at 0
(setv mylist [1 2 3 4])
; tuples are immutable data structures
(setv mytuple (, 1 2))
; dictionaries are key value pairs
(setv dict1 {"key1" 42 "key2" 21})
; :name can be used to define keywords in hy which can be used for keys
(setv dict2 {:key1 41 :key2 20})
; use `get' to get the element at an index/key
(get mylist 1) ;=> 2
(get dict1 "key1") ;=> 42
; Alternatively if keywords were used they can directly be called
(:key1 dict2) ;=> 41

;; functions and other program constructs
; functions are defined using defn, the last sexp is returned by default
(defn greet [name]
  "A simple greeting" ; an optional docstring
  (print "hello " name))

(greet "bilbo") ;=> "hello bilbo"

; functions can take optional arguments as well as keyword arguments
(defn foolists [arg1 &optional [arg2 2]]
  [arg1 arg2])

(foolists 3) ;=> [3 2]
(foolists 10 3) ;=> [10 3]

; you can use rest arguments and kwargs too:
(defn something-fancy [wow &rest descriptions &kwargs props]
  (print "Look at" wow)
  (print "It's" descriptions)
  (print "And it also has:" props))

(something-fancy "My horse" "amazing" :mane "spectacular")
  
; you use apply instead of the splat operators:
(apply something-fancy ["My horse" "amazing"] { "mane" "spectacular" })

; anonymous functions are created using `fn' or `lambda' constructs
; which are similar to `defn'
(map (fn [x] (* x x)) [1 2 3 4]) ;=> [1 4 9 16]

;; Sequence operations
; hy has some builtin utils for sequence operations etc.
; retrieve the first element using `first' or `car'
(setv mylist [1 2 3 4])
(setv mydict {"a" 1 "b" 2})
(first mylist) ;=> 1

; slice lists using slice
(slice mylist 1 3) ;=> [2 3]
; or, in hy 0.11, use cut instead:
(cut mylist 1 3) ;=> [2 3]

; get elements from a list or dict using `get'
(get mylist 1) ;=> 2
(get mydict "b") ;=> 2
; list indexing starts from 0 same as python
; assoc can set elements at keys/indexes
(assoc mylist 2 10) ; makes mylist [1 2 10 4]
(assoc mydict "c" 3) ; makes mydict {"a" 1 "b" 2 "c" 3}
; there are a whole lot of other core functions which makes working with
; sequences fun

;; Python interop
;; import works just like in python
(import datetime)
(import [functools [partial reduce]]) ; imports fun1 and fun2 from module1
(import [matplotlib.pyplot :as plt]) ; doing an import foo as bar
; all builtin python methods etc. are accessible from hy
; a.foo(arg) is called as (.foo a arg)
(.split (.strip "hello world  ")) ;=> ["hello" "world"]

; there is a shortcut for executing multiple functions on a value called the
; "threading macro", denoted by an arrow:
(-> "hello world  " (.strip) (.split)) ;=> ["hello" "world]
; the arrow passes the value along the calls as the first argument, for instance:
(-> 4 (* 3) (+ 2))
; is the same as:
(+ (* 4 3) 2)

; there is also a "threading tail macro", which instead passes the value as the
; second argument. compare:
(-> 4 (- 2) (+ 1)) ;=> 3
(+ (- 4 2) 1) ;=> 3
; to:
(->> 4 (- 2) (+ 1)) ;=> -1
(+ 1 (- 2 4)) ;=> -1

;; Conditionals
; (if condition (body-if-true) (body-if-false)
(if (= passcode "moria")
  (print "welcome")
  (print "Speak friend, and Enter!"))

; nest multiple if else if clauses with cond
(cond
 [(= someval 42)
  (print "Life, universe and everything else!")]
 [(> someval 42)
  (print "val too large")]
 [(< someval 42)
  (print "val too small")])

; group statements with do, these are executed sequentially
; forms like defn have an implicit do
(do
 (setv someval 10)
 (print "someval is set to " someval)) ;=> 10

; create lexical bindings with `let', all variables defined thusly
; have local scope
(let [[nemesis {"superman" "lex luther"
                "sherlock" "moriarty"
                "seinfeld" "newman"}]]
  (for [(, h v) (.items nemesis)]
	(print (.format "{0}'s nemesis was {1}" h v))))

;; classes
; classes are defined in the following way
(defclass Wizard [object]
  [[--init-- (fn [self spell]
             (setv self.spell spell) ; init the spell attr
             None)]
   [get-spell (fn [self]
              self.spell)]])

; or, in hy 0.11:
(defclass Wizard [object]
  (defn --init-- [self spell]
    (setv self.spell spell))

  (defn get-spell [self]
    self.spell))

;; do checkout hylang.org
```

### Further Reading

This tutorial is just a very basic introduction to hy/lisp/python.

Hy docs are here: [http://hy.readthedocs.org](http://hy.readthedocs.org)

Hy's GitHub repo: [http://github.com/hylang/hy](http://github.com/hylang/hy)

On freenode irc #hy, twitter hashtag #hylang