2020-05-22 08:16:55 +03:00
|
|
|
(doc Introspect
|
|
|
|
"Dynamic functions that return information about the s-expressions associated
|
|
|
|
to a binding.")
|
|
|
|
(defmodule Introspect
|
|
|
|
(doc module?
|
|
|
|
"Is this binding a module?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic module? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "defmodule") (car s)))))
|
|
|
|
|
|
|
|
(doc function?
|
2020-05-22 08:16:55 +03:00
|
|
|
"Is this binding a function?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic function? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "defn") (car s)))))
|
|
|
|
|
2020-08-10 22:57:55 +03:00
|
|
|
(doc command?
|
|
|
|
"Is this binding a command?")
|
|
|
|
(defndynamic command? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "command") (car s)))))
|
|
|
|
|
2020-08-11 00:06:46 +03:00
|
|
|
(doc primitive?
|
|
|
|
"Is this binding a primitive?")
|
|
|
|
(defndynamic primitive? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "primitive") (car s)))))
|
|
|
|
|
2020-11-28 14:53:18 +03:00
|
|
|
(doc external?
|
|
|
|
"Is this binding external?")
|
2020-08-11 00:56:28 +03:00
|
|
|
(defndynamic external? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
2020-11-28 14:53:18 +03:00
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "external") (car s)))))
|
2020-08-11 00:56:28 +03:00
|
|
|
|
2020-05-22 08:16:55 +03:00
|
|
|
(doc variable?
|
2020-11-28 14:53:18 +03:00
|
|
|
"Is this binding a variable?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic variable? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
2020-11-28 14:53:18 +03:00
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "def") (car s)))))
|
2020-05-27 20:33:43 +03:00
|
|
|
|
2020-05-22 08:16:55 +03:00
|
|
|
(doc type?
|
2020-11-28 14:53:18 +03:00
|
|
|
"Is this binding a type?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic type? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "deftype") (car s)))))
|
|
|
|
|
|
|
|
(doc struct?
|
2020-05-22 08:16:55 +03:00
|
|
|
"Is this binding a struct?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic struct? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
2020-05-27 22:22:42 +03:00
|
|
|
(if (or (empty? s) (< (length s) 3))
|
2020-05-27 20:33:43 +03:00
|
|
|
false
|
2020-05-27 22:22:42 +03:00
|
|
|
(array? (caddr s)))))
|
2020-05-27 20:33:43 +03:00
|
|
|
|
2020-05-22 08:16:55 +03:00
|
|
|
(doc sumtype?
|
|
|
|
"Is this binding a sumtype?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic sumtype? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
2020-05-27 22:22:42 +03:00
|
|
|
(if (or (empty? s) (< (length s) 3))
|
2020-05-27 20:33:43 +03:00
|
|
|
false
|
2020-05-27 22:22:42 +03:00
|
|
|
(list? (caddr s)))))
|
2020-05-27 20:33:43 +03:00
|
|
|
|
2020-11-28 14:53:18 +03:00
|
|
|
(doc implements? "Does `function` implement `interface`?")
|
|
|
|
(defmacro implements? [interface function]
|
|
|
|
(eval (list 'any?
|
|
|
|
(list 'fn (array 'x) (list '= 'x interface))
|
|
|
|
(list 'meta function "implements"))))
|
|
|
|
|
2020-05-27 20:33:43 +03:00
|
|
|
(doc arity
|
2020-05-22 08:16:55 +03:00
|
|
|
"What's the arity of this binding?
|
|
|
|
|
2021-02-01 19:03:38 +03:00
|
|
|
- When `binding` is a function, returns the number of arguments.
|
|
|
|
- When `binding` is a command, returns the number of arguments.
|
|
|
|
- When `binding` is a primitive, returns the number of arguments.
|
|
|
|
- When `binding` is an interface, returns the number of arguments.
|
|
|
|
- When `binding` is a struct, returns the number of fields.
|
|
|
|
- When `binding` is a sumtype, returns a list of the number of type
|
|
|
|
arguments of each constructor.
|
|
|
|
- Otherwise it returns 0.")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic arity [binding]
|
2021-02-01 19:03:38 +03:00
|
|
|
(let [args (arguments binding)]
|
|
|
|
(if (Introspect.sumtype? binding)
|
|
|
|
(map length args)
|
|
|
|
(length args))))
|
|
|
|
|
|
|
|
(doc arguments
|
|
|
|
"What are the arguments to this binding?
|
|
|
|
|
|
|
|
- When `binding` is a function, returns the argument array.
|
|
|
|
- When `binding` is a command, returns the argument array.
|
|
|
|
- When `binding` is a primitive, returns the argument array.
|
|
|
|
- When `binding` is an interface, returns the argument array.
|
|
|
|
- When `binding` is a struct, returns the fields.
|
|
|
|
- When `binding` is a sumtype, returns a list of the type arguments of each
|
|
|
|
constructor.
|
|
|
|
- Otherwise it returns an empty list.")
|
|
|
|
(defndynamic arguments [binding]
|
2020-05-27 20:33:43 +03:00
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
2020-05-22 08:16:55 +03:00
|
|
|
0
|
2020-05-27 20:33:43 +03:00
|
|
|
(cond
|
2020-08-11 00:56:28 +03:00
|
|
|
(Introspect.external? binding)
|
|
|
|
(if (list? (caddr s))
|
2021-02-01 19:03:38 +03:00
|
|
|
(car (cdaddr s))
|
|
|
|
'())
|
|
|
|
(Introspect.command? binding) (caddr s)
|
|
|
|
(Introspect.primitive? binding) (caddr s)
|
|
|
|
(Introspect.interface? binding) (car (cdaddr s))
|
|
|
|
(Introspect.function? binding) (caddr s)
|
|
|
|
(Introspect.struct? binding) (map car (List.pairs (caddr s)))
|
2020-05-27 20:33:43 +03:00
|
|
|
(Introspect.sumtype? binding) (map (fn [arr]
|
2021-02-01 19:03:38 +03:00
|
|
|
(cadr arr)) (cddr s))
|
|
|
|
'()))))
|
2020-05-27 20:33:43 +03:00
|
|
|
|
2020-05-22 08:16:55 +03:00
|
|
|
(doc macro?
|
|
|
|
"Is this binding a macro?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic macro? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "defmacro") (car s)))))
|
|
|
|
|
2020-05-22 08:16:55 +03:00
|
|
|
(doc dynamic?
|
|
|
|
"Is this binding a dynamic binding?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic dynamic? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
|
|
|
false
|
|
|
|
(or (Dynamic.= (Symbol.from "defdynamic") (car s))
|
|
|
|
(Dynamic.= (Symbol.from "dynamic") (car s))))))
|
|
|
|
|
|
|
|
(doc interface?
|
2020-05-22 08:16:55 +03:00
|
|
|
"Is this binding an interface?")
|
2020-05-27 20:33:43 +03:00
|
|
|
(defndynamic interface? [binding]
|
|
|
|
(let [s (s-expr binding)]
|
|
|
|
(if (empty? s)
|
|
|
|
false
|
|
|
|
(Dynamic.= (Symbol.from "definterface") (car s)))))
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
|
2020-08-11 00:59:26 +03:00
|
|
|
(doc with-copy
|
|
|
|
"Returns a reference to an anonymous 'proxied' variant of `function` in
|
2020-08-19 05:52:56 +03:00
|
|
|
which the argument in position `arg` (indexed from 0) is *copied* from a
|
|
|
|
reference before being passed to `function`:
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
|
|
|
|
```
|
|
|
|
;; Array.reduce expects a function that takes a *ref* in its second argument:
|
|
|
|
;; (Fn [a (Ref b c)] ...)
|
2020-08-11 00:59:26 +03:00
|
|
|
;; so we can't use a function like `+` directly; enter proxy
|
|
|
|
(reduce (with-copy + 2) 0 &[1 2 3])
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
=> 6
|
|
|
|
;; compare this with an inline anonymous function that achieves the same thing:
|
2020-08-11 00:59:26 +03:00
|
|
|
(reduce &(fn [x y] (+ x @y)) 0 &[1 2 3]) === (reduce (with-copy + 2) 0 &[1 2 3])
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
```
|
|
|
|
|
2020-08-11 00:59:26 +03:00
|
|
|
This is useful when using higher-order functions that operate over structures that
|
|
|
|
return *references* to their inhabitants, such as arrays or structs. It allows
|
|
|
|
you to use a function over values without writing a custom anonymous function
|
|
|
|
to handle copying.
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
|
|
|
|
Furthermore, one can define bespoke variants for working with particular
|
2020-08-11 00:59:26 +03:00
|
|
|
higher-order functions. For instace, `reduce` always expacts a reference in the
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
second positon:
|
|
|
|
|
|
|
|
```
|
|
|
|
(defmacro reducer [function]
|
2020-08-11 00:59:26 +03:00
|
|
|
(eval (list with-copy function 2)))
|
|
|
|
(reduce (reducer +) 0 &[1 2 3])
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
=> 6
|
|
|
|
```
|
|
|
|
")
|
2020-08-11 00:59:26 +03:00
|
|
|
(defmacro with-copy [function arg]
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
;; The calls to `eval` around `function` are necessary to ensure we can execute arity.
|
|
|
|
(let [arg-arr (Dynamic.unreduce inc 0 (Introspect.arity (eval function)) (array))
|
2020-08-19 05:52:56 +03:00
|
|
|
;; increment arg by 1 to simulate indexing from 0--since the
|
|
|
|
;; functions we rely on here return counts
|
|
|
|
pos (+ arg 1)
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
local-names (list-to-array-internal (map gensym-local (map Symbol.from arg-arr)) [])
|
2020-08-19 05:52:56 +03:00
|
|
|
target (gensym-local (Symbol.from pos))
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
prox (list 'copy target)
|
|
|
|
call (cons function (map (fn [x] (if (= target x) prox x)) local-names))]
|
2020-08-19 05:52:56 +03:00
|
|
|
(if (> pos (Introspect.arity (eval function)))
|
|
|
|
(macro-error "with-copy error: the specified argument position is greater than the given function's arity.")
|
Add a proxy macro for generating functions for higher-orders
It's a fairly common pattern in Carp to call a higher-order function on
some structure of values, such as an Array. However, these structures,
and their members, all have lifetimes under Carp's memory management
model, which means they expect functions that are mapped over them to
take *a reference to a value* rather than a pure value. Array.reduce is
one example of such a "referential" higher-order, the type of its
function argument is:
```
(Fn [a, (Ref b c)] a)
```
That is, this function takes some pure initial value, then expects to be
called against the members of an array, which are *references* to the
values that are alive throughout the Array's lifetime.
However, one often wants to use a function that operates on pure values
in such contexts, such as +, which forces the programmer to write
anonymous functions that handle copying referenced values to pass them
to the underlying "pure" function:
```
(Array.reduce &(fn [x y] (+ x @y)) 0 &[1 2 3])
```
So, in using some high-order function over some structure in Carp one
usually has to do two things:
1. Wrap the function in a ref
2. Handle copying references into values in order to pass them into some
simpler function that can also be used outside of memory-bound
contexts.
The `proxy` macro captures this pattern. It wraps a given function in a
referenced anonymous function and copies an argument of that function at
a designated position before calling the underlying function. For
example, with `proxy`, the above example becomes:
```
(Array.reduce (proxy + 2) 0 &[1 2 3])
```
The macro effectively gives a name to a common pattern--typically it
will only save the programmer a few characters, but it perhaps makes the
act of using a "function that doesn't care about references" in a
reference dominant context more apparent.
One can also use the macro to develop more specialized macros for
certain higher-orders, since these usually dictate where copying must be
performed. For instance, the `Array.reduce` function argument always
expects the referenced value to occur in the second position, thus one
could write:
```
(defmacro reducer [function] (eval (list proxy function 2)))
```
Then the above code becomes even simpler:
```
(Array.reducer (reducer +) 0 &[1 2 3])
```
Which roughly means, "use the + function (which has no concept of
references) in this reference dependent context".
N.B. The examples using `+` won't work as of now due to current bugs
related to calling `arity` directly on an interface--but a synonym for
plus `add` defined as an explicit function will make all the above work
as expected.
2020-08-08 00:12:43 +03:00
|
|
|
(list 'ref (list 'fn local-names call)))))
|
2020-05-22 08:16:55 +03:00
|
|
|
)
|