From 68ca41b583c6a08949fa72ef5056af6485047b86 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 8 Feb 2023 23:23:38 -0500 Subject: [PATCH] Move the last bit unsorted "list" functions --- .../builtin/functional/apply_fns_to_lists.py | 2 +- mathics/builtin/layout.py | 2 +- mathics/builtin/list/associations.py | 6 +- mathics/builtin/list/constructing.py | 44 +++++++- mathics/builtin/list/eol.py | 16 +-- mathics/builtin/lists.py | 100 ------------------ mathics/builtin/patterns.py | 2 +- .../testing_expressions/list_oriented.py | 95 ++++++++++++++++- 8 files changed, 152 insertions(+), 115 deletions(-) delete mode 100644 mathics/builtin/lists.py diff --git a/mathics/builtin/functional/apply_fns_to_lists.py b/mathics/builtin/functional/apply_fns_to_lists.py index b70fc06e3..fdfa31da4 100644 --- a/mathics/builtin/functional/apply_fns_to_lists.py +++ b/mathics/builtin/functional/apply_fns_to_lists.py @@ -15,7 +15,7 @@ from typing import Iterable from mathics.builtin.base import BinaryOperator, Builtin -from mathics.builtin.lists import List +from mathics.builtin.list.constructing import List from mathics.core.atoms import Integer from mathics.core.convert.expression import to_mathics_list from mathics.core.evaluation import Evaluation diff --git a/mathics/builtin/layout.py b/mathics/builtin/layout.py index f918bd061..2883b0513 100644 --- a/mathics/builtin/layout.py +++ b/mathics/builtin/layout.py @@ -14,7 +14,6 @@ from mathics.builtin.base import BinaryOperator, Builtin, Operator from mathics.builtin.box.layout import GridBox, RowBox, to_boxes -from mathics.builtin.lists import list_boxes from mathics.builtin.makeboxes import MakeBoxes from mathics.builtin.options import options_to_rules from mathics.core.atoms import Real, String @@ -22,6 +21,7 @@ from mathics.core.list import ListExpression from mathics.core.symbols import Symbol from mathics.core.systemsymbols import SymbolMakeBoxes +from mathics.eval.lists import list_boxes from mathics.eval.makeboxes import format_element SymbolSubscriptBox = Symbol("System`SubscriptBox") diff --git a/mathics/builtin/list/associations.py b/mathics/builtin/list/associations.py index 74281bb93..d88b5f65f 100644 --- a/mathics/builtin/list/associations.py +++ b/mathics/builtin/list/associations.py @@ -11,7 +11,6 @@ from mathics.builtin.base import Builtin, Test from mathics.builtin.box.layout import RowBox -from mathics.builtin.lists import list_boxes from mathics.core.atoms import Integer from mathics.core.attributes import A_HOLD_ALL_COMPLETE, A_PROTECTED from mathics.core.convert.expression import to_mathics_list @@ -19,11 +18,14 @@ from mathics.core.expression import Expression from mathics.core.symbols import Symbol, SymbolTrue from mathics.core.systemsymbols import SymbolAssociation, SymbolMakeBoxes, SymbolMissing +from mathics.eval.lists import list_boxes class Association(Builtin): """ - :WMA link:https://reference.wolfram.com/language/ref/Association.html + + :WMA link: + https://reference.wolfram.com/language/ref/Association.html
'Association[$key1$ -> $val1$, $key2$ -> $val2$, ...]' diff --git a/mathics/builtin/list/constructing.py b/mathics/builtin/list/constructing.py index 23acf9185..953a09aad 100644 --- a/mathics/builtin/list/constructing.py +++ b/mathics/builtin/list/constructing.py @@ -11,8 +11,9 @@ from itertools import permutations from mathics.builtin.base import Builtin, IterationFunction, Pattern +from mathics.builtin.box.layout import RowBox from mathics.core.atoms import Integer -from mathics.core.attributes import A_HOLD_FIRST, A_LISTABLE, A_PROTECTED +from mathics.core.attributes import A_HOLD_FIRST, A_LISTABLE, A_LOCKED, A_PROTECTED from mathics.core.convert.expression import to_expression from mathics.core.convert.sympy import from_sympy from mathics.core.element import ElementsProperties @@ -21,7 +22,7 @@ from mathics.core.list import ListExpression from mathics.core.symbols import Atom from mathics.core.systemsymbols import SymbolNormal -from mathics.eval.lists import get_tuples +from mathics.eval.lists import get_tuples, list_boxes class Array(Builtin): @@ -141,6 +142,45 @@ class ConstantArray(Builtin): } +class List(Builtin): + """ + :WMA link:https://reference.wolfram.com/language/ref/List.html + +
+
'List[$e1$, $e2$, ..., $ei$]' +
'{$e1$, $e2$, ..., $ei$}' +
represents a list containing the elements $e1$...$ei$. +
+ + 'List' is the head of lists: + >> Head[{1, 2, 3}] + = List + + Lists can be nested: + >> {{a, b, {c, d}}} + = {{a, b, {c, d}}} + """ + + attributes = A_LOCKED | A_PROTECTED + summary_text = "form a list" + + def eval(self, elements, evaluation): + """List[elements___]""" + # Pick out the elements part of the parameter elements; + # we we will call that `elements_part_of_elements__`. + # Note that the parameter elements may be wrapped in a Sequence[] + # so remove that if when it is present. + elements_part_of_elements__ = elements.get_sequence() + return ListExpression(*elements_part_of_elements__) + + def eval_makeboxes(self, items, f, evaluation): + """MakeBoxes[{items___}, + f:StandardForm|TraditionalForm|OutputForm|InputForm|FullForm]""" + + items = items.get_sequence() + return RowBox(*list_boxes(items, f, evaluation, "{", "}")) + + class Normal(Builtin): """ diff --git a/mathics/builtin/list/eol.py b/mathics/builtin/list/eol.py index 8b40325b2..79c9c0176 100644 --- a/mathics/builtin/list/eol.py +++ b/mathics/builtin/list/eol.py @@ -11,7 +11,6 @@ from mathics.builtin.base import BinaryOperator, Builtin from mathics.builtin.box.layout import RowBox -from mathics.builtin.lists import list_boxes from mathics.core.atoms import Integer, Integer0, Integer1, String from mathics.core.attributes import ( A_HOLD_FIRST, @@ -44,7 +43,7 @@ SymbolSequence, SymbolSet, ) -from mathics.eval.lists import delete_one, delete_rec +from mathics.eval.lists import delete_one, delete_rec, list_boxes from mathics.eval.parts import ( _drop_span_selector, _take_span_selector, @@ -1276,15 +1275,18 @@ class Position(Builtin): >> Position[{1, 2, 2, 1, 2, 3, 2}, 2] = {{2}, {3}, {5}, {7}} - Find positions upto 3 levels deep + Find positions upto 3 levels deep: + >> Position[{1 + Sin[x], x, (Tan[x] - y)^2}, x, 3] = {{1, 2, 1}, {2}} - Find all powers of x + Find all powers of x: + >> Position[{1 + x^2, x y ^ 2, 4 y, x ^ z}, x^_] = {{1, 2}, {4}} - Use Position as an operator + Use Position as an operator: + >> Position[_Integer][{1.5, 2, 2.5}] = {{2}} """ @@ -1327,7 +1329,9 @@ def callback(level, pos): class Prepend(Builtin): """ - :WMA link:https://reference.wolfram.com/language/ref/Prepend.html + + :WMA link: + https://reference.wolfram.com/language/ref/Prepend.html
'Prepend[$expr$, $item$]' diff --git a/mathics/builtin/lists.py b/mathics/builtin/lists.py deleted file mode 100644 index ed37c8869..000000000 --- a/mathics/builtin/lists.py +++ /dev/null @@ -1,100 +0,0 @@ -# -*- coding: utf-8 -*- -""" -List Functions - Miscellaneous - -Functions here will eventually get moved to more suitable subsections. -""" - -from mathics.builtin.base import Builtin, Test -from mathics.builtin.box.layout import RowBox -from mathics.core.attributes import A_LOCKED, A_PROTECTED -from mathics.core.exceptions import InvalidLevelspecError -from mathics.core.list import ListExpression -from mathics.eval.lists import list_boxes -from mathics.eval.parts import python_levelspec - - -class LevelQ(Test): - """ - - :WMA link: - https://reference.wolfram.com/language/ref/LevelQ.html - -
-
'LevelQ[$expr$]' -
tests whether $expr$ is a valid level specification. -
- - >> LevelQ[2] - = True - >> LevelQ[{2, 4}] - = True - >> LevelQ[Infinity] - = True - >> LevelQ[a + b] - = False - """ - - summary_text = "test whether is a valid level specification" - - def test(self, ls): - try: - start, stop = python_levelspec(ls) - return True - except InvalidLevelspecError: - return False - - -class List(Builtin): - """ - :WMA link:https://reference.wolfram.com/language/ref/List.html - -
-
'List[$e1$, $e2$, ..., $ei$]' -
'{$e1$, $e2$, ..., $ei$}' -
represents a list containing the elements $e1$...$ei$. -
- - 'List' is the head of lists: - >> Head[{1, 2, 3}] - = List - - Lists can be nested: - >> {{a, b, {c, d}}} - = {{a, b, {c, d}}} - """ - - attributes = A_LOCKED | A_PROTECTED - summary_text = "specify a list explicitly" - - def eval(self, elements, evaluation): - """List[elements___]""" - # Pick out the elements part of the parameter elements; - # we we will call that `elements_part_of_elements__`. - # Note that the parameter elements may be wrapped in a Sequence[] - # so remove that if when it is present. - elements_part_of_elements__ = elements.get_sequence() - return ListExpression(*elements_part_of_elements__) - - def eval_makeboxes(self, items, f, evaluation): - """MakeBoxes[{items___}, - f:StandardForm|TraditionalForm|OutputForm|InputForm|FullForm]""" - - items = items.get_sequence() - return RowBox(*list_boxes(items, f, evaluation, "{", "}")) - - -class NotListQ(Test): - """ - :WMA link:https://reference.wolfram.com/language/ref/NotListQ.html - -
-
'NotListQ[$expr$]' -
returns true if $expr$ is not a list. -
- """ - - summary_text = "test if an expression is not a list" - - def test(self, expr): - return expr.get_head_name() != "System`List" diff --git a/mathics/builtin/patterns.py b/mathics/builtin/patterns.py index d1d0fe571..677a635e2 100644 --- a/mathics/builtin/patterns.py +++ b/mathics/builtin/patterns.py @@ -49,7 +49,6 @@ PatternObject, PostfixOperator, ) -from mathics.builtin.lists import InvalidLevelspecError from mathics.core.atoms import Integer, Number, Rational, Real, String from mathics.core.attributes import ( A_HOLD_ALL, @@ -60,6 +59,7 @@ ) from mathics.core.element import EvalMixin from mathics.core.evaluation import Evaluation +from mathics.core.exceptions import InvalidLevelspecError from mathics.core.expression import Expression, SymbolVerbatim from mathics.core.list import ListExpression from mathics.core.pattern import Pattern, StopGenerator diff --git a/mathics/builtin/testing_expressions/list_oriented.py b/mathics/builtin/testing_expressions/list_oriented.py index 2513370f7..f8f4ec031 100644 --- a/mathics/builtin/testing_expressions/list_oriented.py +++ b/mathics/builtin/testing_expressions/list_oriented.py @@ -5,15 +5,19 @@ from mathics.builtin.base import Builtin, Test from mathics.core.atoms import Integer, Integer1, Integer2 from mathics.core.evaluation import Evaluation +from mathics.core.exceptions import InvalidLevelspecError from mathics.core.expression import Expression from mathics.core.rules import Pattern from mathics.core.symbols import Atom, SymbolFalse, SymbolTrue from mathics.core.systemsymbols import SymbolSubsetQ +from mathics.eval.parts import python_levelspec class ArrayQ(Builtin): """ - :WMA: https://reference.wolfram.com/language/ref/ArrayQ.html + + :WMA: + https://reference.wolfram.com/language/ref/ArrayQ.html
'ArrayQ[$expr$]' @@ -114,6 +118,57 @@ class IntersectingQ(Builtin): summary_text = "test whether two lists have common elements" +class LevelQ(Test): + """ +
+
'LevelQ[$expr$]' +
tests whether $expr$ is a valid level specification. This function \ + is primarily used in function patterns for specifying type of a \ + parameter. +
+ + >> LevelQ[2] + = True + >> LevelQ[{2, 4}] + = True + >> LevelQ[Infinity] + = True + >> LevelQ[a + b] + = False + + We will define MyMap with the "level" parameter as a synonym for the \ + Builtin Map equivalent: + + >> MyMap[f_, expr_, Pattern[levelspec, _?LevelQ]] := Map[f, expr, levelspec] + + >> MyMap[f, {{a, b}, {c, d}}, {2}] + = {{f[a], f[b]}, {f[c], f[d]}} + + >> Map[f, {{a, b}, {c, d}}, {2}] + = {{f[a], f[b]}, {f[c], f[d]}} + + But notice that when we pass an invalid level specification, MyMap \ + does not match and therefore does not pass the arguments through to 'Map'. \ + So we do not see the error message that 'Map' would normally produce + + >> Map[f, {{a, b}, {c, d}}, x] + : Level specification x is not of the form n, {n}, or {m, n}. + = Map[f, {{a, b}, {c, d}}, x] + + >> MyMap[f, {{a, b}, {c, d}}, {1, 2, 3}] + = MyMap[f, {{a, b}, {c, d}}, {1, 2, 3}] + """ + + summary_text = "test whether is a valid level specification" + + def test(self, ls): + try: + start, stop = python_levelspec(ls) + return True + except InvalidLevelspecError: + return False + + class MatrixQ(Builtin): """ @@ -183,6 +238,42 @@ class MemberQ(Builtin): summary_text = "test whether an element is a member of a list" +class NotListQ(Test): + """ +
+
'NotListQ[$expr$]' +
returns 'True' if $expr$ is not a list. This function is primarily \ + used in function patterns for specifying type of a parameter. +
+ + Consider this definition for taking the deriviate 'Sin' of a function: + + >> MyD[Sin[f_],x_?NotListQ] := D[f,x]*Cos[f] + = + + We use "MyD" above to distinguish it from the Builtin 'D'. Now let's try it: + + >> MyD[Sin[2 x], x] + = 2 Cos[2 x] + + And compare it with the Builtin deriviative function 'D': + + >> D[Sin[2 x], x] + = 2 Cos[2 x] + + Note however the pattern only matches if the $x$ parameter is not a list: + + >> MyD[{Sin[2], Sin[4]}, {1, 2}] + = MyD[{Sin[2], Sin[4]}, {1, 2}] + + """ + + summary_text = "test if an expression is not a list" + + def test(self, expr): + return expr.get_head_name() != "System`List" + + class SubsetQ(Builtin): """ @@ -244,7 +335,7 @@ class SubsetQ(Builtin): } summary_text = "test if a list is a subset of another list" - def eval(self, expr, subset, evaluation): + def eval(self, expr, subset, evaluation: Evaluation): "SubsetQ[expr_, subset___]" if isinstance(expr, Atom):