function.lisp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. (import core/prelude ())
  2. (defun slot? (symb)
  3. "Test whether SYMB is a slot. For this, it must be a symbol, whose
  4. contents are `<>`.
  5. ### Example
  6. ```cl
  7. > (slot? '<>)
  8. out = true
  9. > (slot? 'not-a-slot)
  10. out = false
  11. ```"
  12. (and (symbol? symb) (= (.> symb "contents") "<>")))
  13. (defmacro cut (&func)
  14. "Partially apply a function FUNC, where each `<>` is replaced by an
  15. argument to a function. Values are evaluated every time the resulting
  16. function is called.
  17. ### Example
  18. ```cl
  19. > (define double (cut * <> 2))
  20. > (double 3)
  21. out = 6
  22. ```"
  23. (let [(args '())
  24. (call '())]
  25. (for-each item func
  26. (if (slot? item)
  27. (with (symb (gensym))
  28. (push! args symb)
  29. (push! call symb))
  30. (push! call item)))
  31. `(lambda ,args ,call)))
  32. (defmacro cute (&func)
  33. "Partially apply a function FUNC, where each `<>` is replaced by an
  34. argument to a function. Values are evaluated when this function is
  35. defined.
  36. ### Example
  37. ```cl
  38. > (define double (cute * <> 2))
  39. > (double 3)
  40. out = 6
  41. ```"
  42. (let ((args '())
  43. (vals '())
  44. (call '()))
  45. (for-each item func
  46. (with (symb (gensym))
  47. (push! call symb)
  48. (if (slot? item)
  49. (push! args symb)
  50. (push! vals `(,symb ,item)))))
  51. `(let ,vals (lambda ,args ,call))))
  52. (defmacro -> (x &funcs)
  53. "Chain a series of method calls together. If the list contains `<>`
  54. then the value is placed there, otherwise the expression is invoked
  55. with the previous entry as an argument.
  56. ### Example
  57. ```cl
  58. > (-> '(1 2 3)
  59. . (map succ <>)
  60. . (map (cut * <> 2) <>))
  61. out = (4 6 8)
  62. ```"
  63. (with (res x)
  64. (for-each form funcs
  65. (let* [(symb (gensym))
  66. (body (if (and (list? form) (any slot? form))
  67. (map (lambda (x) (if (slot? x) symb x)) form)
  68. `(,form ,symb)))]
  69. (set! res `((lambda (,symb) ,body) ,res))))
  70. res))
  71. (defun invokable? (x)
  72. "Test if the expression X makes sense as something that can be applied
  73. to a set of arguments.
  74. ### Example
  75. ```cl
  76. > (invokable? invokable?)
  77. out = true
  78. > (invokable? nil)
  79. out = false
  80. > (invokable? (setmetatable {} { :__call (lambda (x) (print! \"hello\")) }))
  81. out = true
  82. ```"
  83. (or (function? x)
  84. (and (table? x)
  85. (table? (getmetatable x))
  86. (invokable? (.> (getmetatable x) :__call)))))
  87. (defun compose (f g)
  88. "Return the pointwise composition of functions F and G.
  89. ### Example:
  90. ```cl
  91. > ((compose (cut + <> 2) (cut * <> 2))
  92. . 2)
  93. out = 6
  94. ```"
  95. (if (and (invokable? f)
  96. (invokable? g))
  97. (lambda (x) (f (g x)))
  98. nil))
  99. (defun comp (&fs)
  100. "Return the pointwise composition of all functions in FS.
  101. ### Example:
  102. ```cl
  103. > ((comp succ (cut + <> 2) (cut * <> 2))
  104. . 2)
  105. out = 7
  106. ```"
  107. (reduce compose (lambda (x) x) fs))
  108. (defun id (x)
  109. "Return the value X unmodified.
  110. ### Example
  111. ```cl
  112. > (map id '(1 2 3))
  113. out = (1 2 3)
  114. ```"
  115. x)
  116. (defun as-is (x)
  117. "Return the value X unchanged.
  118. ### Example
  119. ```cl
  120. > (map as-is '(1 2 3))
  121. out = (1 2 3)
  122. ```"
  123. x)
  124. (defun const (x)
  125. "Return a function which always returns X. This is equivalent to the
  126. `K` combinator in SK combinator calculus.
  127. ### Example
  128. ```cl
  129. > (define x (const 1))
  130. > (x 2)
  131. out = 1
  132. > (x \"const\")
  133. out = 1
  134. ```"
  135. (lambda () x))
  136. (defun call (x key &args)
  137. "Index X with KEY and invoke the resulting function with ARGS.
  138. ### Example
  139. ```cl
  140. > (define tbl { :add + })
  141. > (call tbl :add 1 2 3)
  142. out = 6
  143. ```"
  144. (apply (.> x key) args))
  145. (defun self (x key &args)
  146. "Index X with KEY and invoke the resulting function with X and ARGS.
  147. ### Example
  148. ```cl
  149. > (define tbl { :get (lambda (self key) (.> self key))
  150. . :x 1
  151. . :y 2 })
  152. > (self tbl :get :x)
  153. out = 1
  154. ```"
  155. (apply (.> x key) x args))