next | previous | forward | backward | up | top | index | toc | Macaulay2 website
Macaulay2Doc > The Macaulay2 language > using hooks

using hooks

Hooks in Macaulay2 are a type of dynamic dispatch, that is, a way to provide different implementations of methods and events and select which implementation to use depending on characteristics of the input arguments.

The addHook method allows the user to attach multiple hooks, or strategies, for computing a method key such as (intersect, Ideal, Ideal), or a symbol.

Hooks can be functions or methods, and they can accept optional arguments.

i1 : f = {a=>3, c=>12} >> opts -> val -> if val == 1 then opts.a + opts.c;
i2 : g = method(Options => {b => 5});
i3 : g ZZ := opts -> val -> if val == 2 then opts.b + 1;
i4 : h = val -> if val == 3 then 24;
i5 : foo = method(Options => true);
i6 : addHook((foo, ZZ), f)

o6 = f

o6 : FunctionClosure
i7 : addHook((foo, ZZ), g, Strategy => "G")

o7 = g

o7 : MethodFunctionWithOptions
i8 : addHook((foo, ZZ), h)

o8 = h

o8 : FunctionClosure

The method runHooks runs all the hooks until one of them returns a non-null value. Hooks are run in order starting from the most recently added hook. Because of this, each hook should be able to decide quickly whether it is the right implementation for the input, and if not should return null.

Any optional argument passed to runHooks that matches a key in the OptionTable of a hook will be passed on to it. Otherwise it will be ignored.

i9 : foo ZZ := true >> opts -> args -> runHooks((foo, ZZ), args, opts);
i10 : debugLevel = 1

o10 = 1
i11 : assert( foo 1 == 15 )
 -- (foo,ZZ) with Strategy => 2 from h
 -- (foo,ZZ) with Strategy => G from g
 -- (foo,ZZ) with Strategy => 0 from f
i12 : assert( foo(2, b => 9) == 10 )
 -- (foo,ZZ) with Strategy => 2 from h
 -- (foo,ZZ) with Strategy => G from g
i13 : assert( foo 3 == 24 )
 -- (foo,ZZ) with Strategy => 2 from h

The function hooks lists all hooks attached to a method key or symbol, in the order in which they were added, that is, the opposite order in which they are run.

i14 : hooks(foo, ZZ)

o14 = {0 => (foo, ZZ, Strategy => 0)}
      {1 => (foo, ZZ, Strategy => G)}
      {2 => (foo, ZZ, Strategy => 2)}

o14 : NumberedVerticalList

Hooks are automatically assigned an integer which can be used as the value of the Strategy option to specify only one strategy to run.

i15 : assert( foo(3, Strategy => 2) == 24 )
 -- (foo,ZZ) with Strategy => 2 from h
i16 : assert( foo(2, Strategy => "G") == 6 )
 -- (foo,ZZ) with Strategy => G from g

If the code for a hook was read from a file, then it can be retrieved with the code function.

i17 : hooks(quotient, Ideal, Ideal)

o17 = {0 => (quotient, Ideal, Ideal, Strategy => Quotient)}
      {1 => (quotient, Ideal, Ideal, Strategy => Iterate) }
      {2 => (quotient, Ideal, Ideal, Strategy => Monomial)}

o17 : NumberedVerticalList
i18 : code 1

o18 = -- code for method: quotient(Ideal,Ideal)
      /usr/share/Macaulay2/Saturation.m2:213:29-219:71: --source code:
          Iterate => (opts, I, J) -> (
              R := ring I;
              -- TODO: extend this into a strategy for any PID
              if R === ZZ then return ideal sub(gcd I_* / gcd flatten(I_*, J_*), ZZ);
              fold(first entries mingens J, ideal 1_R, (f, M1) ->
                  if generators(f * M1) % generators I == 0 then M1
                  else intersect(M1, quotient(I, ideal f, opts, Strategy => Quotient)))),

See also

Menu