書替え規則において、ある特定の「関数名」はマーカーとして機能します。 本節はそのようなマーカーの全リストです。 まずパターン中で働くマーカーのリスト、 次に規則の右辺で働くマーカーをリストします。
ただ一種のマーカー `import(x)' は、規則そのものとして働きます。 ここで `x' は変数名で、その変数にストアされた他の規則集合が、 インポート先の規則に継承されます。 例えば、`[f(a+b) := f(a) + f(b), f(a b) := a f(b) :: real(a)]' が 変数 `linearF' にストアされている状態で、 `[f(0) := 0, import(linearF)]' は3つの規則全てを適用します。 インポートした規則を若干修正することが可能で、 `import(x, v1, x1, v2, x2, ...)' は 規則集合 x をインポートして、 出現する @c{$v_1$} v1 (変数または関数名)を全て x1 に置換します(@c{$v_2$} v2 以降も同様)。 (@c{$v_1$} v1 が関数名ならば、@c{$x_1$} x1 も関数名か無名関数 `< >' でなければなりません。 Specifying Operators 参照 。) 例えば、`[g(0) := 0, import(linearF, f, g)]' は、 線形規則を f にではなく g に適用します。 `import(x)' はネストできますが、import-with-renaming 機能は 下位のインポートを適切にリネームできないかも知れません。
パターン中で許される特殊関数は下記のとおりです。
quote
とは異なり、
引数の `x1,x2,...' はパターンとして扱われます。
引数を同様に「plain 的」に扱いたい場合は、次のように
それぞれ別の plain
で囲んでやる必要があります。
`plain(plain(-a) + plain(b c))'
def
を指定しなければなりません。
マッチングのとき、
オプショナル引数が抜かされていると def
の値が採られます。
例えば、パターン `f(opt(a,0), b, opt(c,b))' は
`f(b)', `f(a,b)', `f(a,b,c)' にマッチします。
省略された引数に対して(訳注: 後で参照するとき)、
この例ではゼロや b がデフォルト値として供給されます。
後者の例では、
文字どおりの変数 b がデフォルトになることに注意してください。
それはメタ変数 b にマッチした式ではありません。
言換えれば、デフォルト値 def は実質的に quote されていると言えます。
cons
, except that the last element
is matched to h, with the remaining elements matched
to t.
apply
pattern. For example,
`apply(f,x)' matches any function call, `apply(quote(f),x)'
matches any call to the function `f', `apply(f,[a,b])'
matches any function call with exactly two arguments, and
`apply(quote(f), cons(a,cons(b,x)))' matches any call
to the function `f' with two or more arguments. Another
way to implement the latter, if the rest of the rule does not
need to refer to the first two arguments of `f' by name,
would be `apply(quote(f), x :: vlen(x) >= 2)'.
Here's a more interesting sample use of apply
:
apply(f,[x+n]) := n + apply(f,[x]) :: in(f, [floor,ceil,round,trunc]) :: integer(n)Note, however, that this will be slower to match than a rule set with four separate rules. The reason is that Calc sorts the rules of a rule set according to top-level function name; if the top-level function is
apply
, Calc must try the
rule for every single formula and sub-formula. If the top-level
function in the pattern is, say, floor
, then Calc invokes
the rule only for sub-formulas which are calls to floor
.
Formulas normally written with operators like +
are still
considered function calls: apply(f,x)
matches `a+b'
with `f = add', `x = [a,b]'.
You must use apply
for meta-variables with function names
on both sides of a rewrite rule: `apply(f, [x]) := f(x+1)'
is not correct, because it rewrites `spam(6)' into
`f(7)'. The righthand side should be `apply(f, [x+1])'.
Also note that you will have to use no-simplify (m O)
mode when entering this rule so that the apply
isn't
evaluated immediately to get the new rule `f(x) := f(x+1)'.
Or, use s e to enter the rule without going through the stack,
or enter the rule as `apply(f, [x]) := apply(f, [x+1]) :: 1'.
条件つきの書替え規則 参照 .
規則の右辺で働く特殊関数は次のとおりです。
quote
is invisible. However, quote
has the special
property in Calc that its argument is not evaluated. Thus,
while it will not work to put the rule `t(a) := typeof(a)'
on the stack because `typeof(a)' is evaluated immediately
to produce `t(a) := 100', you can use quote
to
protect the righthand side: `t(a) := quote(typeof(a))'.
(条件つきの書替え規則 参照 , for another trick for
protecting rules from evaluation.)
plain
is useful is the rule, `q(x) := quote(x)', trying to expand a
shorthand notation for the quote
function. This rule will
not work as shown; instead of replacing `q(foo)' with
`quote(foo)', it will replace it with `foo'! The correct
rule would be `q(x) := plain(quote(x))'.
cons
is a regular
Calc function which normally does this anyway; the only way cons
is treated specially by rewrites is that cons
on the righthand
side of a rule will be evaluated even if default simplifications
have been turned off.
cons
except putting h at the end of
the vector t.
apply
is also a regular Calc function.
cons
and apply
are always
treated. However, there is a slight difference: `cons(2+3, [])'
with default simplifications off will be converted to `[2+3]',
whereas `eval(cons(2+3, []))' will be converted to `[5]'.
There are also some special functions you can use in conditions.
evalsimp
or
evalextsimp
as described above to invoke higher levels
of simplification. The
result of x is then bound to the meta-variable v. As
usual, if this meta-variable has already been matched to something
else the two values must be equal; if the meta-variable is new then
it is bound to the result of the expression. This variable can then
appear in later conditions, and on the righthand side of the rule.
In fact, v may be any pattern in which case the result of
evaluating x is matched to that pattern, binding any
meta-variables that appear in that pattern. Note that let
can only appear by itself as a condition, or as one term of an
`&&' which is a whole condition: It cannot be inside
an `||' term or otherwise buried.
The alternate, equivalent form `let(v, x)' is also recognized.
Note that the use of `:=' by let
, while still being
assignment-like in character, is unrelated to the use of `:='
in the main part of a rewrite rule.
As an example, `f(a) := g(ia) :: let(ia := 1/a) :: constant(ia)'
replaces `f(a)' with `g' of the inverse of `a', if
that inverse exists and is constant. For example, if `a' is a
singular matrix the operation `1/a' is left unsimplified and
`constant(ia)' fails, but if `a' is an invertible matrix
then the rule succeeds. Without let
there would be no way
to express this rule that didn't have to invert the matrix twice.
Note that, because the meta-variable `ia' is otherwise unbound
in this rule, the let
condition itself always "succeeds"
because no matter what `1/a' evaluates to, it can successfully
be bound to ia
.
Here's another example, for integrating cosines of linear
terms: `myint(cos(y),x) := sin(y)/b :: let([a,b,x] := lin(y,x))'.
The lin
function returns a 3-vector if its argument is linear,
or leaves itself unevaluated if not. But an unevaluated lin
call will not match the 3-vector on the lefthand side of the let
,
so this let
both verifies that y
is linear, and binds
the coefficients a
and b
for use elsewhere in the rule.
(It would have been possible to use `sin(a x + b)/b' for the
righthand side instead, but using `sin(y)/b' avoids gratuitous
rearrangement of the argument of the sine.)
Similarly, here is a rule that implements an inverse-erf
function. It uses root
to search for a solution. If
root
succeeds, it will return a vector of two numbers
where the first number is the desired solution. If no solution
is found, root
remains in symbolic form. So we use
let
to check that the result was indeed a vector.
ierf(x) := y :: let([y,z] := root(erf(a) = x, a, .5))
matches
is a standard Calc function, it
can appear anywhere in a condition. But if it appears alone or
as a term of a top-level `&&', then you get the special
extra feature that meta-variables which are bound to things
inside p can be used elsewhere in the surrounding rewrite
rule.
The only real difference between `let(p := v)' and
`matches(v, p)' is that the former evaluates `v' using
the default simplifications, while the latter does not.
remember
appears as a condition in a rule, then when that rule succeeds
the original expression and rewritten expression are added to the
front of the rule set that contained the rule. If the rule set
was not stored in a variable, remember
is ignored. The
lefthand side is enclosed in quote
in the added rule if it
contains any variables.
For example, the rule `f(n) := n f(n-1) :: remember' applied
to `f(7)' will add the rule `f(7) := 7 f(6)' to the front
of the rule set. The rule set EvalRules
works slightly
differently: There, the evaluation of `f(6)' will complete before
the result is added to the rule set, in this case as `f(7) := 5040'.
Thus remember
is most useful inside EvalRules
.
It is up to you to ensure that the optimization performed by
remember
is safe. For example, the rule `foo(n) := n
:: evalv(eatfoo) > 0 :: remember' is a bad idea (evalv
is
the function equivalent of the = command); if the variable
eatfoo
ever contains 1, rules like `foo(7) := 7' will
be added to the rule set and will continue to operate even if
eatfoo
is later changed to 0.
Go to the first, previous, next, last section, table of contents.
利用度数