You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/concepts.rst
+278-3Lines changed: 278 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,23 +5,298 @@ Concepts
5
5
6
6
.. lpy:currentns:: basilisp.core
7
7
8
+
This document outlines some of the key high-level concepts of Basilisp, most of which behave identically to their Clojure counterparts.
9
+
The sections below tend to focus on how each of these concepts can be applied while using Basilisp.
10
+
For those looking for more of a philosophical discussion of each of these concepts, you may find the corresponding `Clojure documentation <https://clojure.org/reference>`_ enlightening as it frequently emphasizes the *motivations* for the various concepts more heavily than this documentation.
11
+
8
12
.. _data_structures:
9
13
10
14
Data Structures
11
15
---------------
12
16
13
-
TBD
17
+
Basilisp provides a comprehensive set of immutable data structures and a set of scalar types inherited from the host Python environment.
18
+
19
+
.. _nil:
20
+
21
+
nil
22
+
^^^
23
+
24
+
The value ``nil`` corresponds to Python's ``None``.
25
+
Any type is potentially ``nil``, though many Basilisp functions are intended to handle ``nil`` values gracefully.
26
+
Only the value ``nil`` and the :ref:`boolean <boolean_values>` value ``false`` are considered logical false in conditions.
27
+
28
+
.. seealso::
29
+
30
+
:lpy:fn:`nil?`
31
+
32
+
.. _boolean_values:
33
+
34
+
Boolean Values
35
+
^^^^^^^^^^^^^^
36
+
37
+
The values ``true`` and ``false`` correspond to Python's ``True`` and ``False``, respectively.
38
+
They are singleton instances of :external:py:class:`bool`
39
+
Only the values ``nil`` and ``false`` are considered logical false in conditions.
40
+
41
+
.. seealso::
42
+
43
+
:lpy:fn:`false?`, :lpy:fn:`true?`
44
+
45
+
.. _numbers:
46
+
47
+
Numbers
48
+
^^^^^^^
49
+
50
+
Basilisp exposes all of the built-in numeric types from Python and operations with those values match Python unless otherwise noted.
51
+
52
+
Integral values correspond to Python's arbitrary precision :external:py:class:`int` type.
53
+
54
+
Floating point values are represented by :external:py:class:`float`.
55
+
For fixed-point arithmetic with user specified precision (corresponding with Clojure's ``BigDecimal`` type float suffixed with an ``M``), Basilisp uses Python's :external:py:class:`decimal.Decimal` class.
56
+
57
+
Complex numbers are backed by Python's :external:py:class:`complex`.
58
+
59
+
Ratios are represented by Python's :external:py:class:`fractions.Fraction` type.
60
+
61
+
.. seealso::
62
+
63
+
:ref:`arithmetic_division`
64
+
65
+
.. _strings_and_byte_strings:
66
+
67
+
Strings and Byte Strings
68
+
^^^^^^^^^^^^^^^^^^^^^^^^
69
+
70
+
Basilisp's string type is Python's base :external:py:class:`str` type.
71
+
Python's byte string type :external:py:class:`bytes` is also supported.
72
+
73
+
.. note::
74
+
75
+
Basilisp does not have a first class character type since there is no equivalent in Python.
76
+
:ref:`reader_character_literals` can be read from source code, but will be converted into single-character strings.
77
+
78
+
.. seealso::
79
+
80
+
:lpy:ns:`basilisp.string` for an idiomatic string manipulation library
81
+
82
+
.. _keywords:
83
+
84
+
Keywords
85
+
^^^^^^^^
86
+
87
+
Keywords are symbolic identifiers which always evaluate to themselves.
88
+
Keywords consist of a name and an optional namespace, both of which are strings.
89
+
The textual representation of a keyword includes a single leading ``:``, which is not part of the name or namespace.
90
+
91
+
Keywords are also functions of one or 2 arguments, roughly equivalent to calling :lpy:fn:`get` on a map or set with an optional default value argument.
92
+
If the first argument is a :ref:`map <maps>`, then looks up the value associated with the keyword in the map.
93
+
If the first argument is a :ref:`set <sets>`, then looks up if the keyword is a member of the set and returns itself if so.
94
+
Returns the default value or ``nil`` (if no default value is specified) if either check fails.
95
+
96
+
.. code-block::
97
+
98
+
(def m {:kw 1 :other 2})
99
+
(:kw m) ;; => 1
100
+
(get m :kw) ;; => 1
101
+
(:some-kw m) ;; => nil
102
+
(:some-kw m 3) ;; => 3
103
+
(get m :some-kw 3) ;; => 3
104
+
105
+
.. note::
106
+
107
+
Keyword values are interned and keywords are compared by identity, not by value.
108
+
109
+
.. warning::
110
+
111
+
Keywords can be created programmatically via :lpy:fn:`keyword` which may not be able to be read back by the :ref:`reader`, so use caution when creating keywords programmatically.
Symbols are symbolic identifiers which are typically used to refer to something else.
123
+
Symbols consist of a name and an optional namespace, both strings.
124
+
125
+
Symbols, like :ref:`keywords`, can also be called like a function similar to :lpy:fn:`get` on a map or set with an optional default value argument.
126
+
If the first argument is a :ref:`map <maps>`, then looks up the value associated with the symbol in the map.
127
+
If the first argument is a :ref:`set <sets>`, then looks up if the symbol is a member of the set and returns itself if so.
128
+
Returns the default value or ``nil`` (if no default value is specified) if either check fails.
129
+
130
+
.. code-block::
131
+
132
+
(def m {'sym 1 'other 2})
133
+
('sym m) ;; => 1
134
+
(get m 'sym) ;; => 1
135
+
('some-sym m) ;; => nil
136
+
('some-sym m 3) ;; => 3
137
+
(get m 'sym 3) ;; => 3
138
+
139
+
.. note::
140
+
141
+
Basilisp will always try to resolve unquoted symbols, so be sure to wrap symbols in as ``(quote sym)`` or ``'sym`` if you just want a symbol.
142
+
143
+
.. warning::
144
+
145
+
Symbols can be created programmatically via :lpy:fn:`symbol` which may not be able to be read back by the :ref:`reader`, so use caution when creating symbols programmatically.
Basilisp includes the following data structures, all of which are both immutable and persistent.
157
+
APIs which "modify" collections in fact produce new collections which may or may not share some structure with the original collection.
158
+
As a result of their immutability, all of these collections are thread-safe.
159
+
160
+
Many of Basilisp's built-in collection types support creating :ref:`transient <transients>` versions of themselves for more efficient modification in a tight loop.
Vectors are sequential collections much more similar to Python lists or arrays in other languages.
199
+
Vectors return their count in ``O(1)`` time via :lpy:fn:`count`.
200
+
:lpy:fn:`conj` adds items to the end of a vector.
201
+
Random access to vector elements by index (via :lpy:fn:`get` or :lpy:fn:`nth`) is ``O(log32(n))``.
202
+
You can reverse a vector in constant time using :lpy:fn:`rseq`.
203
+
204
+
Vectors be called like a function similar to :lpy:fn:`nth` with an index and an optional default value, returning the value at the specified index if found.
205
+
Returns the default value or ``nil`` (if no default value is specified) otherwise.
Seqs are an interface for sequential types that generalizes iteration to that of a singly-linked list.
279
+
However, because the functionality is defined in terms of an interface, many other data types can also be manipulated as Seqs.
280
+
The :lpy:fn:`seq` function creates an optimal Seq for the specific input type -- all built-in collection types are "Seqable".
281
+
282
+
Most of Basilisp's Seq functions operate on Seqs lazily, rather than eagerly.
283
+
This is frequently a desired behavior, but can be confusing when debugging or exploring data at the REPL.
284
+
You can force a Seq to be fully realized by collecting it into a concrete :ref:`collection type <collection_types>` or by using :lpy:fn:`doall` (among other options).
285
+
286
+
Seqs bear more than a passing resemblance to a stateful iterator type, but have some distinct advantages.
287
+
In particular, Seqs are immutable once realized and thread-safe, meaning Seqs can be be easily passed around with abandon.
288
+
289
+
Lazy seqs can be created using using the :lpy:fn:`lazy-seq` macro.
290
+
291
+
.. warning::
292
+
293
+
There are several possible gotchas when using Seqs over mutable Python :py:class:`collections.abc.Iterable` types.
294
+
Because Seqs are immutable, Seqs created from mutable collections can diverge from their source collection if that collection is modified after realizing the Seq.
295
+
Also, because Seqs are realized lazily, it is possible that a Seq created from a mutable collection will capture changes to that collection after the initial Seq is created.
Copy file name to clipboardExpand all lines: docs/differencesfromclojure.rst
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,7 +43,7 @@ In Clojure, this optimistic equality comparison is performed by the ``==`` funct
43
43
44
44
.. note::
45
45
46
-
Basilisp's ``=`` will perform as expected when using Python :external:py:class:`decimal.Decimal` typed :ref:`floating_point_numbers`.
46
+
Basilisp's ``=`` will perform as expected when using Python :external:py:class:`decimal.Decimal` typed :ref:`floating-point numbers <numbers>`.
47
47
48
48
.. seealso::
49
49
@@ -75,7 +75,7 @@ That said, there are some fundamental differences and omissions in Basilisp that
75
75
Reader
76
76
------
77
77
78
-
* :ref:`Numbers <numeric_literals>`
78
+
* :ref:`Numbers <reader_numeric_literals>`
79
79
80
80
* Python integers natively support unlimited precision, so there is no difference between regular integers and those suffixed with ``N`` (which are read as ``BigInt``\s in Clojure).
81
81
* Floating point numbers are read as Python ``float``\s by default and subject to the limitations of that type on the current Python VM.
@@ -84,7 +84,7 @@ Reader
84
84
* Python natively supports Complex numbers.
85
85
The reader will return a complex number for any integer or floating point literal suffixed with ``J``.
86
86
87
-
* :ref:`Characters <character_literals>`
87
+
* :ref:`Characters <reader_character_literals>`
88
88
89
89
* Python does not support character types, so characters are returned as single-character strings.
Copy file name to clipboardExpand all lines: docs/pyinterop.rst
+8-4Lines changed: 8 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -243,15 +243,15 @@ Type hints may be applied to :lpy:form:`def` names, function arguments and retur
243
243
.. warning::
244
244
245
245
Due to the complexity of supporting multi-arity functions in Python, only return annotations are preserved on the arity dispatch function.
246
-
Return annotations are combined as by ``typing.Union``, so ``typing.Union[str, str] == str``.
246
+
Return annotations are combined as by :external:py:obj:`typing.Union`, so ``typing.Union[str, str] == str``.
247
247
The annotations for individual arity arguments are preserved in their compiled form, but they are challenging to access programmatically.
248
248
249
-
.. _arithmeticdivision:
249
+
.. _arithmetic_division:
250
250
251
-
Arithmetic division
251
+
Arithmetic Division
252
252
-------------------
253
253
254
-
:lpy:fn:`basilisp.core/quot`, :lpy:fn:`basilisp.core/rem` and :lpy:fn:`basilisp.core/mod` functions.
254
+
.. lpy:currentns::basilisp.core
255
255
256
256
The Python native quotient ``//`` and modulo ``%`` operators may yield different results compared to their Java counterpart's long division and modulo operators. The discrepancy arises from Python's choice of floored division (`src <http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html>`_, `archived <https://web.archive.org/web/20100827160949/http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html>`_) while Java employs truncated division for its calculations (refer to the to the `Wikipedia Modulo page <https://en.wikipedia.org/wiki/Modulo>`_ for a a comprehensive list of available division formulae).
257
257
@@ -260,3 +260,7 @@ In Clojure, the ``clojure.core/quot`` function utilizes Java's long division ope
260
260
Basilisp has chosen to adopt the same mathematical formulae as Clojure for these three functions, rather than using the Python's built in operators under all cases. This approach offers the advantage of enhanced cross-platform compatibility without requiring modification, and ensures compatibility with examples in `ClojureDocs <https://clojuredocs.org/>`_.
261
261
262
262
Users still have the option to use the native :external:py:func:`operator.floordiv`, i.e. Python's ``//`` operator, if they prefer so.
0 commit comments