higher order operatives?

125 views
Skip to first unread message

Mariano Guerra

unread,
Mar 26, 2012, 12:10:10 PM3/26/12
to kl...@googlegroups.com
hi,

one question that came to my mind at some point.

given that some standard higher order applicatives exist
(map/reduce/filter/fold)

are there standard higher order operatives?
does that makes sense?
if it makes sense and there aren't standard ones, can we think of some?

Manuel Simoni

unread,
Mar 26, 2012, 12:41:31 PM3/26/12
to kl...@googlegroups.com

Andres Navarro

unread,
Mar 26, 2012, 6:34:54 PM3/26/12
to klisp
> given that some standard higher order applicatives exist
> (map/reduce/filter/fold)
>
> are there standard higher order operatives?
> does that makes sense?

Well, I think it does make sense. However there's probably more to
this matter than what we can see right now.

I'll start with a couple of simple examples (which are by the way,
just regular extensions to the ones you mention)

operative filter:

($define! $op-filter
($vau (op . ls) denv
($let ((op (eval op denv)))
(filter ($lambda (x) (eval (list op x) denv))
ls))))

And then we can do (in a standard environment):

($define! $bound?
($vau (sym) denv
(eval (list $binds? denv sym) denv)))

($op-filter $bound? $lambda $define! a) => ($lambda $define!)

($define! $op-for-each
($vau (op . ls) denv
($let ((op (eval op denv)))
(apply for-each
(cons ($lambda xs (eval (cons op xs) denv))
ls)))))

And then we can do:

($op-for-each $define! (a b c) (1 2 (+ a b))) => #inert
a => 1
b => 2
c => 3

While these are toy examples, the underlying concept is useful in a
number of situations.

A couple of points to keep in mind:

- These don't actually accept only operatives as operands, instead
they take any object that evaluates in the dynamic environment to an
operative (of course, operatives are self-evaluating so no problem
there). While the alternative is possible it would make these a lot
less practical.
- These are operatives that take operatives (more or less, see above).
The common ones (filter, for-each, etc) are in Kernel lingo,
applicatives that take applicatives as arguments. But there could be
useful higher order combiners that involve both types (i.e.
applicatives that take operatives, and operatives that take
applicatives).

> if it makes sense and there aren't standard ones, can we think of some?

- Higher order applicatives are useful because they capture common use
cases (mapping, filtering, reduction) of a common types of
applicatives (projection functions, predicates, n-ary operators). I
feel that we need a lot more work with operatives in order to classify
different types of operatives and use cases to warrant a more
widespread use of higher order operatives.


Andres Navarro

Brandon Bloom

unread,
Mar 13, 2014, 8:22:10 PM3/13/14
to kl...@googlegroups.com
I feel that we need a lot more work with operatives in order to classify
different types of operatives and use cases to warrant a more
widespread use of higher order operatives.

Sorry to dig up a 2 year old thread, but I'm curious: Has your experience uncovered any particularly useful higher-order operatives? What about higher-order combiners that welcome both applicative and operative combiners as arguments? Thanks!

Oto Havle

unread,
Mar 15, 2014, 7:23:15 AM3/15/14
to kl...@googlegroups.com
On 03/14/2014 01:22 AM, Brandon Bloom wrote:
> I feel that we need a lot more work with operatives in order to
> classify
> different types of operatives and use cases to warrant a more
> widespread use of higher order operatives.
>
>
> Sorry to dig up a 2 year old thread, but I'm curious: Has your
> experience uncovered any particularly useful higher-order operatives?

As much as I would like to hear the opposite, my personal experience
is no. Only "wrap" comes close, as it works with wide range of
operatives. There exists a paper about variants of wrap providing
lazy and parallel evaluation of arguments:


http://faculty.cs.byu.edu/~jay/conferences/2013-tfp/proceedings/tfp2013_submission_20.pdf

> What about higher-order combiners that welcome both applicative and
> operative combiners as arguments? Thanks!
>

Usually, each operative defines its own little language with its own
syntax and semantics (see e.g. $let, $if, $define!). It is hard to
imagine a high-order combiner which could be useful with all of
them. Related question: Are there high-order macros?

Regards,

Oto Havle.

Brandon Bloom

unread,
Mar 15, 2014, 2:45:47 PM3/15/14
to kl...@googlegroups.com
Another good place to look is Mathematica. In Mathematica, you can use
expressions with "non-standard evaluation rules" in higher-order ways.


Interestingly, it doesn't seem to suffer from the "operand capture" issue:
(see JShutt's dissertation, section 5.2.1)

In[58]:= call[f_, x_] := f[x]
In[59]:= call[Cos, 0]
Out[59]= 1

In[73]:= Unevaluated[5 + 10]
Out[73]= Unevaluated[5 + 10]

In[77]:= call[Hold, Unevaluated[5 + 10]]
Out[77]= Hold[5 + 10]


I've used this feature to parameterize functions with a
short-circuiting operator like And & Or:

In[71]:= call2[f_, x_, y_] := f[x, y]

In[65]:= Or[(Print[1]; True), (Print[2]; True)]
During evaluation of In[65]:= 1
Out[65]= True

In[66]:= call2[Or, (Print[1]; True), (Print[2]; True)]
During evaluation of In[66]:= 1
During evaluation of In[66]:= 2
Out[66]= True

In[76]:= call2[Or, Unevaluated[(Print[1]; True)], Unevaluated[(Print[2]; True)]]
During evaluation of In[76]:= 1
Out[76]= True


Interestingly, there are (at least) two types of quoting operators
that prove useful:

http://reference.wolfram.com/mathematica/ref/Hold.html
http://reference.wolfram.com/mathematica/ref/Unevaluated.html

Andres Navarro

unread,
Mar 20, 2014, 12:50:19 PM3/20/14
to kl...@googlegroups.com
As much as I would like to hear the opposite, my personal experience
is no. Only "wrap" comes close, as it works with wide range of
operatives. There exists a paper about variants of wrap providing
lazy and parallel evaluation of arguments:


http://faculty.cs.byu.edu/~jay/conferences/2013-tfp/proceedings/tfp2013_submission_20.pdf



That's quite interesting, i hadn't come across it before.
 
What about higher-order combiners that welcome both applicative and
operative combiners as arguments? Thanks!


Usually, each operative defines its own little language with its own
syntax and semantics (see e.g. $let, $if, $define!). It is hard to
imagine a high-order combiner which could be useful with all of
them.

While it's true that operatives in general can have arbitrary syntax and semantics, one
can still identity families.  In those cases, a higher-order combiner sometimes can be
conceived.  For example one that takes a short-circuiting boolean function (like $and? or
$or?), a let-family binder ($let, $let*, $letrec, $letrec*, $let-safe, BUT NOT $let-redirect which has
a different syntax), a one hand conditional ($when or $unless), etc.  In all these cases, the
higher order operative needs to know beforehand the syntax of the accepted operatives, but
they are still quite useful from time to time.

Regards,
Andres Navarro

Brandon Bloom

unread,
Mar 20, 2014, 2:18:35 PM3/20/14
to kl...@googlegroups.com
For example one that takes a short-circuiting boolean function (like $and? or $or?),

$and? and $or? are already defined as variadic, but let's imagine that they were defined as binary operators. In that case, I could imagine a higher-order $foldl operative. Still, it would be a relatively awkward and error prone construct.

I think that I'd rather work with regular functions and first-class code blocks instead. Again, looking at Mathematica, I note that Unevaluated[x] is akin to ($quote x), but Hold[x] is a different thing entirely. Unevaluated (and quote too) prevent evaluation one-time. It's like a little wrapper that gets pealed off immediately upon passing through the evaluator. However, Hold, sticks around. Then, there is this curious "Evaluate" form that acts as an unquote inside Hold expressions, forcing evaluation. In effect, Hold lets you turn an active expression in to a self-evaluating inactive expression, modulo Evaluate subexpressions:

In[9]:= Sqrt[Unevaluated[3 + 6]]
Out[9]= 3


In[10]:= Sqrt[Hold[3 + 6]]
Out[10]= Sqrt[Hold[3 + 6]]

In[11]:= Sqrt[Hold[Evaluate[3 + 6]]]
Out[11]= Sqrt[Hold[9]]

Now, Mathematica is a rewriting system, so things are a tad different, but this idea holds promise for me. Instead of having first-class operatives, we could have first-class blocks of code. Then a "higher-order operative" would simply be a higher-order function that accepts blocks of code as arguments.

Andres Navarro

unread,
Mar 21, 2014, 12:52:27 AM3/21/14
to kl...@googlegroups.com


On Mar 20, 2014 3:19 PM, "Brandon Bloom" <brandon...@gmail.com> wrote:

>
> Now, Mathematica is a rewriting system, so things are a tad different, but this idea holds promise for me. Instead of having first-class operatives, we could have first-class blocks of code. Then a "higher-order operative" would simply be a higher-order function that accepts blocks of code as arguments.

What operations would these "blocks of code" have? If the only operation they support is "eval" they aren't different from promises which kernel already has.

While smalltalk uses this idea of "blocks of code" quite heavily, in the lisp world (even in the scheme camp) there is a tendency to use special forms (operatives in kernel).  It's only natural that in some cases higher order things need to be done with them.

As you say, working with operatives in this way is hard at first, but no one forces you to do it :) You can always use applicatives, thunks, promises or whatever thing you can come up with.

Regards,
Andres Navarro

Reply all
Reply to author
Forward
0 new messages