base.joy 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. (* base.joy -- basic operators and combinators for Joy.
  2. Copyright © 2016 Eric Bavier <bavier@member.fsf.org>
  3. Joy is free software; you can redistribute it and/or modify it under
  4. the terms of the GNU General Public License as published by the Free
  5. Software Foundation; either version 3 of the License, or (at your
  6. option) any later version.
  7. Joy is distributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  9. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  10. License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with Joy. If not, see <http://www.gnu.org/licenses/>.
  13. *)
  14. (* Various useful operators and combinators written in terms of Joy
  15. primitives. *)
  16. DEFINE
  17. (* ===== Stack manipulation operators ===== *)
  18. newstack == [] unstack ;
  19. popd == [pop] dip ;
  20. dupd == [dup] dip ;
  21. swapd == [swap] dip ;
  22. dup2 == dup [[dup] dip swap] dip ;
  23. pop2 == pop pop ;
  24. popop == pop2 ;
  25. dig1 == swap ;
  26. dig2 == [] cons cons dip ;
  27. dig3 == [] cons cons cons dip ;
  28. dig4 == [] cons cons cons cons dip ;
  29. dig == dig2 ;
  30. rolldown == dig2 ;
  31. bury1 == swap ;
  32. bury2 == [[] cons cons] dip swap i ;
  33. bury3 == [[] cons cons cons] dip swap i ;
  34. bury4 == [[] cons cons cons cons] dip swap i ;
  35. bury == bury2 ;
  36. rollup == bury2 ;
  37. flip2 == swap ;
  38. flip3 == [] take take take i ;
  39. flip4 == [] take take take take i ;
  40. flip == flip3 ;
  41. rotate == flip3 ;
  42. (* ===== General combinators ===== *)
  43. (* We could use 'dup dip pop' to define i as exmplained in
  44. "Mathematical Foundation of Joy", but it is not efficient
  45. as the straighforward definition. *)
  46. i == stack cdr swap infra unstack ;
  47. i2 == [dip] dip i ;
  48. dip == stack cddr swap infra cons unstack ;
  49. dip0 == i ;
  50. dip1 == dip ;
  51. dip2 == [[] cons cons] dip dip i ;
  52. dip3 == [[] cons cons cons] dip dip i ;
  53. dip4 == [[] cons cons cons cons] dip dip i ;
  54. dipd == dip2 ;
  55. dipdd == dip3 ;
  56. nullary == stack cdr swap infra car ;
  57. unary == stack cdr swap infra car popd ;
  58. (* TODO: deprecate these in favor of "unary2", "unary3" *)
  59. app1 == i ;
  60. app2 == dup rollup i [i] dip ;
  61. app3 == dup rollup i [app2] dip ;
  62. branch == choice i ;
  63. ifte == [[stack] dip infra car] dipd branch ;
  64. shunt == [swons] step ; # See literature for description
  65. (* The definition 'b == concat i' is elegant, but it is also
  66. costly (I think? TODO: check). *)
  67. b == [i] dip i ;
  68. cleave == [nullary] dip swap [nullary] dip swap ;
  69. k == [pop] dip i ;
  70. w == [dup] dip i ;
  71. c == [swap] dip i ;
  72. (* [S | L [P]] : Step through the list L, unconsing the first
  73. element, placing it on the top S and executing the quoted
  74. program P. *)
  75. step ==
  76. [pop null]
  77. [pop pop]
  78. [[uncons] dip dup dipd]
  79. tailrec ;
  80. (* [S | I [P]] :: Execute quoted program P I times. *)
  81. times ==
  82. swap
  83. [0 <=]
  84. [pop pop]
  85. [pred [dup dip] dip]
  86. tailrec ;
  87. (* ===== List operators ===== *)
  88. car == uncons pop ;
  89. cdr == unswons pop ;
  90. cddr == cdr cdr ;
  91. cadr == cdr car ;
  92. caddr == cddr car ;
  93. first == car ;
  94. second == cadr ;
  95. third == caddr ;
  96. rest == cdr ;
  97. leaf == list not ;
  98. unit == [] cons ;
  99. unpair == uncons uncons pop ;
  100. pairlist == [] cons cons ;
  101. take == [dip] cons cons ;
  102. concat == swap swoncat ;
  103. swoncat == reverse shunt ;
  104. swons == swap cons ;
  105. unswons == uncons swap ;
  106. null == [list] [[] =] [0 =] ifte ;
  107. nulld == [null] dip ;
  108. consd == [cons] dip ;
  109. swonsd == [swons] dip ;
  110. unconsd == [uncons] dip ;
  111. unswonsd == [unswons] dip unswons swapd ;
  112. null2 == nulld null or ;
  113. cons2 == swapd cons consd ;
  114. uncons2 == unconsd uncons swapd ;
  115. swons2 == swapd swons swonsd ;
  116. zip ==
  117. [null2]
  118. [pop pop []]
  119. [uncons2]
  120. [[pairlist] dip cons]
  121. linrec ;
  122. sum == 0 swap [+ ] step ;
  123. product == 1 swap [* ] step ;
  124. size == 0 swap [pop succ] step ;
  125. size2 == 0 swap [size + ] step ; # two levels of nesting
  126. (* reverse the aggregate on top of the stack *)
  127. reverse == [] swap [swons] step ;
  128. (* [S | L V O] => [S | V'], where L is a list, V is an initial
  129. value, and O is a quoted binary operator. *)
  130. fold == swapd step ;
  131. (* [S | L P] => [S | B], where B is true if applying the predicate
  132. P to each element of L produces true, otherwise false. It does
  133. not short-circuit. *)
  134. every == [i and] cons true fold ;
  135. all == every ; # reference name
  136. (* [S | L P] => [S | B], where B is true if applying the predicate
  137. P to any element of L produces true, otherwise false. It does
  138. not short-circuit. *)
  139. any == [i or] cons false fold ;
  140. some == any ; # reference name
  141. (* Treat each element of an aggregate as a new stack, and apply
  142. the given unary operator to it, resulting in a new aggregate
  143. of the results *)
  144. map ==
  145. [] # initialize accumulator
  146. [pop pop null]
  147. [rollup pop pop]
  148. [[unswons [] cons] dipd # pull out first and create new list
  149. dupd [infra] dipd # exec copy of quotation on this
  150. rolldown car swons] # add it to accumulator
  151. tailrec
  152. reverse ;
  153. (* [S | L L' O] => [S | L''] where L'' is the list resulting from
  154. applying the binary operator O to respective pairs of elements
  155. from L and L'. L'' is the same length as the shortest of L and
  156. L'. *)
  157. map2 ==
  158. [] # initialize accumulator
  159. [pop pop null2]
  160. [[pop pop pop] dip] # Remove operator, L, and L'
  161. [[[unswons] dipd swapd # pull out first of L
  162. [unswons [] cons] dipd # pull out first of L'
  163. swonsd # make a list of the two
  164. dup [infra] dip] # exec copy of quotation on this
  165. dip
  166. rolldown car swons] # add it to accumulator
  167. tailrec
  168. reverse ;
  169. (* [S | L L'] => [S | B], where B is true if every element of list
  170. L compares equal to each respective element of L', otherwise
  171. false. *)
  172. equal ==
  173. [[size] app2 =]
  174. [ true [[[list] app2] [equal] [=] ifte] fold ]
  175. [false]
  176. ifte ;
  177. (* [S | L I] -> [S | L'] where L' is L with I elements removed
  178. from the front. *)
  179. list-tail ==
  180. [0 <=]
  181. [pop]
  182. [pred [cdr] dip]
  183. tailrec ;
  184. (* [S | L I] -> [S | L'] where L' is the first I items of L. *)
  185. list-head ==
  186. [] rollup # initialize accumulator
  187. [0 <=]
  188. [pop pop reverse]
  189. [pred [uncons] dip [swons] dipd]
  190. tailrec ;
  191. at == list-tail car ;
  192. of == swap at ;
  193. (* ===== Boolean and Mathematic operators ===== *)
  194. pred == 1 - ;
  195. succ == 1 + ;
  196. 1+ == 1 + ;
  197. 1- == 1 - ;
  198. true == [true] car ;
  199. false == [false] car ;
  200. >= == dup2 > [=] dip or ;
  201. <= == dup2 < [=] dip or ;
  202. != == = not ;
  203. or == [pop true] [] branch ;
  204. and == [] [pop false] branch ;
  205. not == false true choice ;
  206. xor == dup2 or rollup and not and ;
  207. max == dup2 > rollup choice ;
  208. min == dup2 < rollup choice ;
  209. sign == [0 >] [1] [[0 <] [-1] [0] ifte] ifte ;
  210. (* [S | Y X] -> [S | D M] where Y = D*X + M *)
  211. divmod ==
  212. [0] rollup # initialize marker list
  213. [<] # When Y < X
  214. [pop swap] # Remove X, bring markers to front
  215. [dup [-] dip # Recurse with Y<-Y-X ...
  216. [1 swons] dipd] # and mark
  217. [[+] infra] # Accumulate division markers
  218. linrec # [S | M [D]]
  219. car swap ; # [S | D M]
  220. / == divmod pop ;
  221. % == divmod swap pop ;
  222. * == # WARNING: Only for positive integers
  223. dup2 min [max] dip # Put the larger number on top
  224. [0 =]
  225. [pop pop 0]
  226. [pred dupd]
  227. [+]
  228. linrec ;
  229. exp ==
  230. [0 =]
  231. [pop pop 1]
  232. [pred dupd]
  233. [*]
  234. linrec ;
  235. sum-up-to == [0 =] [pop 0] [dup 1 -] [+] linrec ;
  236. fact == [0 =] [pop 1] [dup 1 -] [*] linrec ;
  237. (* ===== Recursion combinators ===== *)
  238. (* [S | [I} [T] [E1] [E2]] - Like the ifte combinator it executes
  239. I, and if that yields true it executes T. Otherwise it
  240. executes E1, then it recurses with all 4 parts, and finally it
  241. executes E2. *)
  242. # For example:
  243. # fact ==
  244. # [0 =]
  245. # [pop 1]
  246. # [dup 1 -]
  247. # [*]
  248. # linrec .
  249. # becomes:
  250. # fact ==
  251. # [ [pop 0 =]
  252. # [pop pop 1]
  253. # [ [dup 1 -] dip
  254. # dup i
  255. # * ]
  256. # ifte ]
  257. # dup i .
  258. make-linrec ==
  259. [[[pop] car swons] app2] dipd # [[E2] [E1] [pop T] [pop I] | S]
  260. [i] car swons [dup] car swons [dip] car swons cons
  261. [ifte] cons cons cons # [[ifte [[E1] dip dup i E2] [pop T] [pop I] | S]
  262. ;
  263. linrec == make-linrec dup i ;
  264. make-tailrec ==
  265. [[[pop] car swons] app2] dip
  266. [dip dup i] cons
  267. [ifte] cons cons cons ;
  268. tailrec == make-tailrec dup i ;
  269. (* ===== IO operators ===== *)
  270. newline == '\n putch ;
  271. putchars == [putch] step ;
  272. putstrings == [putchars] step ;
  273. END