hissp.macros module#
Hisspâs bundled tag
and macro
metaprograms.
While completely optional, these bring Hissp up to a minimal standard of
practical utility without adding dependencies. As a convenience, they
are automatically made available unqualified
in the Lissp REPL
, but
this is not true of modules.
Hisspâs standalone property
means the compiled output of code written
using these metaprograms need not have Hissp installed at run time to
work, only the Python standard library. All helper code must therefore
be inlined, resulting in larger expansions than might otherwise be
necessary.
They also have no prerequisite initialization, beyond what is available
in a standard Python module. For example, a _macro_
namespace need
not be available for defmacro
. Itâs smart enough to check for the
presence of _macro_
(at compile time) in its expansion context, and
inline the initialization code when required.
With the exception of mix
, which is a text macro
specifically made
for creating a Python injection
, the other metaprograms eschew
expansions of any of their arguments to a Python injection
(other than
the standard
symbol
or string literal fragment
cases), relying
only on the built-in special forms quote
and lambda
, which makes
their expansions compatible with advanced rewriting macros that process
the Hissp expansions of other macros.
(The -[#
and my#
tags are also something of an
exception, as one argument is written in Python to begin with.)
That only goes for arguments and doesnât apply to inlined helper
functions in the expansions that contain no user code, because thatâs no
worse than using an opaque name imported from somewhere else. if-else
is one such example, expanding to a lambda containing an
injected conditional expression
, that is called immediately.
_macro_#
Hisspâs bundled tag and macro namespace.
See hissp.macros
.
- hissp.macros._macro_.BQzHASH_(symbol)#
B#
âbytesymbolâConverts a
parsed object
of typestr
tobytes
.#> B#|bytes!| >>> b'bytes!' b'bytes!' #> B#oops! ; Works directly on symbols, but beware munging. >>> b'oopsQzBANG_' b'oopsQzBANG_' #> B#"oops!" ; You probably wanted b# instead. >>> b"('oops!')" b"('oops!')" #> B#.#"OK" ; Note the .#. >>> b'OK' b'OK' #> B#|\xff || "\n'" BBQ| ; Escapes allowed, like b#. >>> b'\xff | "\n\'" BBQ' b'\xff | "\n\'" BBQ'
See also:
b#
.
- hissp.macros._macro_.HQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
hissp.
asH#
.
- hissp.macros._macro_.MQzHASH_(M)#
M#
âDecimalâ Exact decimal tag.Abbreviation for
decimal.Decimal
, with ademunge
for symbols.Mnemonic: âMoneyâ. Chosen to resemble Clojureâs
BigDecimal
literal, likely inspired by C⯠where âDâ was taken for double-precision floats, leaving âMâ as the next best letter in âdeciMalâ.The usual construction has a trailing underscore to avoid going through a float literal, which would have limited precision:
#> M#1.23e6_ >>> # Decimal('1.23E+6') ... __import__('pickle').loads(b'cdecimal\nDecimal\n(V1.23E+6\ntR.') Decimal('1.23E+6')
When converting a read-time constant float, go through
str
first:#> M#.#(repr math..tau) >>> # Decimal('6.283185307179586') ... __import__('pickle').loads(b'cdecimal\nDecimal\n(V6.283185307179586\ntR.') Decimal('6.283185307179586')
See also:
Q#
.
- hissp.macros._macro_.OQzHASH_(expr)#
O#
âthunkâ Makeexpr
an anonymous function body with no parameters.See also:
X#
.
- hissp.macros._macro_.QQzHASH_(Q)#
Q#
âRationalâ Exact fraction tag.Abbreviation for
fractions.Fraction
, with ademunge
for symbols.Mnemonic: âuotient.
#> Q#2/3 >>> # Fraction(2, 3) ... __import__('pickle').loads(b'cfractions\nFraction\n(V2/3\ntR.') Fraction(2, 3)
See also:
M#
.
- hissp.macros._macro_.QzAT_(*xs)#
@
âlist ofâMnemonic: @rray list.
Creates the
list
from each expressionâs result. A:*
unpacks the next argument:#> (@ :* "AB" (math..sqrt 9) :* "XY" 2 1) >>> # QzAT_ ... (lambda *xs: [*xs])( ... *('AB'), ... __import__('math').sqrt( ... (9)), ... *('XY'), ... (2), ... (1)) ['A', 'B', 3.0, 'X', 'Y', 2, 1]
See also:
#
,%
,en#
,operator.matmul
.
- hissp.macros._macro_.QzAT_QzHASH_(name, ns='')#
@#
âattribute ofâ Looks up attribute in a namespace.Mnemonic: @tribute.
#> (.join "" (filter @##'intersection (set "abc") "abracadabra")) >>> ('').join( ... filter( ... __import__('operator').attrgetter( ... 'intersection')( ... set( ... ('abc'))), ... ('abracadabra'))) 'abacaaba' #> (let (eggs &#@#'upper ; Unary compatible with &#. #.. spam 'intersection) ; Lookup need not be constant. #.. ;; Various chaining techniques. Note unary @# and '. #.. @##'__class__.__name__ (-> (set) @#spam @#'__doc__ eggs)) >>> # let ... ( ... lambda eggs=__import__('functools').partial( ... __import__('operator').attrgetter( ... 'upper'), ... ), ... spam='intersection': ... __import__('operator').attrgetter( ... '__class__.__name__')( ... # QzH_QzGT_ ... eggs( ... __import__('operator').attrgetter( ... '__doc__')( ... __import__('operator').attrgetter( ... spam)( ... set(), ... ), ... ))) ... )() 'builtin_function_or_method'
- hissp.macros._macro_.QzAT_sQzHASH_(names)#
@s\#
âattribute namesâdestruct->
helper shorthand. Destructures a namespace using the binding names as the attributes.#> (destruct-> (types..SimpleNamespace : spam 1 foo 2) #.. (ors whole #.. ors @s#(spam foo)) #.. (print whole spam foo)) >>> # destructQzH_QzGT_ ... # hissp.macros.._macro_.letQzH_from ... (lambda whole, spam, foo: ... print( ... whole, ... spam, ... foo) ... )( ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzxlqqwo2w__data=__import__('types').SimpleNamespace( ... spam=(1), ... foo=(2)): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... # ors ... _Qzxlqqwo2w__data, ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzxlqqwo2w__data=# hissp.macros.._macro_.QzH_QzGT_ ... # ors ... _Qzxlqqwo2w__data: ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').attrgetter( ... 'spam')( ... _Qzxlqqwo2w__data, ... ), ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').attrgetter( ... 'foo')( ... _Qzxlqqwo2w__data, ... ), ... ) ... )(), ... ) ... )()) namespace(spam=1, foo=2) 1 2
- hissp.macros._macro_.QzBANG_QzHASH_(key, items='')#
!#
âlook up inâ Gets an item from items.Mnemonic: !tem.
#> (define first &#!#0) ;Gets an item by index. >>> # define ... __import__('builtins').globals().update( ... first=__import__('functools').partial( ... __import__('operator').itemgetter( ... (0)), ... )) #> (first "abc") >>> first( ... ('abc')) 'a' #> !##(slice None None -1) "abc" ;Slicing without injection. >>> __import__('operator').itemgetter( ... slice( ... None, ... None, ... (-1)))( ... ('abc')) 'cba' #> !##'+ (dict : foo 2 + 1) ;These also work on dicts. >>> __import__('operator').itemgetter( ... 'QzPLUS_')( ... dict( ... foo=(2), ... QzPLUS_=(1))) 1 #> (-> '(foo bar) !#1 .upper !#1) ;Unary compatible with ->. >>> # QzH_QzGT_ ... __import__('operator').itemgetter( ... (1))( ... __import__('operator').itemgetter( ... (1))( ... ('foo', ... 'bar',), ... ).upper(), ... ) 'A'
See also:
operator.getitem
,operator.itemgetter
,[#
,set!
,&#
,@#
.
- hissp.macros._macro_.QzBANG_sQzHASH_(names)#
!s\#
âitem namesâdestruct->
helper shorthand. Destructures a mapping using the binding names as the keys.#> (destruct-> (dict : spam 1 foo 2) #.. (ors whole #.. ors !s#(spam foo)) #.. (print whole spam foo)) >>> # destructQzH_QzGT_ ... # hissp.macros.._macro_.letQzH_from ... (lambda whole, spam, foo: ... print( ... whole, ... spam, ... foo) ... )( ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzxlqqwo2w__data=dict( ... spam=(1), ... foo=(2)): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... # ors ... _Qzxlqqwo2w__data, ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzxlqqwo2w__data=# hissp.macros.._macro_.QzH_QzGT_ ... # ors ... _Qzxlqqwo2w__data: ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... 'spam')( ... _Qzxlqqwo2w__data, ... ), ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... 'foo')( ... _Qzxlqqwo2w__data, ... ), ... ) ... )(), ... ) ... )()) {'spam': 1, 'foo': 2} 1 2
- hissp.macros._macro_.QzCOLON_QzAT_QzHASH_(decoration, definition)#
:@##
âdecoratorâ appliesdecoration
to definition & reassigns.definition
form must assign an attribute identified by its first arg. Expands to adefine
, meaning decorators can stack.Decorator syntax is for definitions, like
define
anddefun
, and would work on any definition macro that has the definition qualname as its first argument (notdefmacro
, butdefun
can target the_macro_
namespace if it exists).Use
zap@
to decorate an attribute after its definition.#> :@##.swapcase #..:@##.title #..(define spam 'spam) ; Unlike Python def, not always a function. >>> # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... spam=# hissp.macros.._macro_.progn ... (# hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... spam=# hissp.macros.._macro_.progn ... (# define ... __import__('builtins').globals().update( ... spam='spam'), ... spam.title()) [-1]), ... spam.swapcase()) [-1]) #> spam >>> spam 'sPAM'
- hissp.macros._macro_.QzET_QzHASH_(callableQzPLUS_args)#
&#
Abbreviation forfunctools.partial
.
- hissp.macros._macro_.QzHASH_(*xs)#
#
âset ofâ Mnemonic: Hash (#) set.Creates the
set
from each expressionâs result. A:*
unpacks the next argument.#> (# 1 :* (@ 1 2 3) 4) ;Set, with unpacking. >>> # QzHASH_ ... (lambda *xs: {*xs})( ... (1), ... *# QzAT_ ... (lambda *xs: [*xs])( ... (1), ... (2), ... (3)), ... (4)) {1, 2, 3, 4}
- hissp.macros._macro_.QzH_QzGT_(expr, *forms)#
->
âThread-firstâ.Converts a pipeline to function calls by recursively threading expressions as the first argument of the next form. Non-tuple forms (typically function identifiers) will be wrapped in a tuple. Can make chained method calls easier to read.
#> (_macro_.-> 'x '(A a) 'B '(C c cc)) >>> _macro_.QzH_QzGT_( ... 'x', ... ('A', ... 'a',), ... 'B', ... ('C', ... 'c', ... 'cc',)) ('C', ('B', ('A', 'x', 'a')), 'c', 'cc') #> (-> 'a set (en#list 'bc) (en#tuple 'de)) >>> # QzH_QzGT_ ... (lambda *_Qz6rfwttvx__xs: ... tuple( ... _Qz6rfwttvx__xs) ... )( ... (lambda *_Qz6rfwttvx__xs: ... list( ... _Qz6rfwttvx__xs) ... )( ... set( ... 'a'), ... 'bc'), ... 'de') ([{'a'}, 'bc'], 'de')
- hissp.macros._macro_.QzH_QzLT_QzGT_QzGT_(expr, *forms)#
-<>>
âThread-throughâ.Converts a pipeline to function calls by recursively threading expressions into the next form at the first point indicated with
:<>
, or at the last if no:<>
is found. Non-tuple forms (typically function identifiers) will be wrapped in a tuple first. Can replace partial application in some cases.#> (_macro_.-<>> 'x 'A '(:<> b bb) '(C c cc)) >>> _macro_.QzH_QzLT_QzGT_QzGT_( ... 'x', ... 'A', ... (':<>', ... 'b', ... 'bb',), ... ('C', ... 'c', ... 'cc',)) ('C', 'c', 'cc', (('A', 'x'), 'b', 'bb')) #> (-<>> 'a set (en#list 'bc) (en#tuple 'de :<> 'fg :<>)) >>> # QzH_QzLT_QzGT_QzGT_ ... (lambda *_Qz6rfwttvx__xs: ... tuple( ... _Qz6rfwttvx__xs) ... )( ... 'de', ... (lambda *_Qz6rfwttvx__xs: ... list( ... _Qz6rfwttvx__xs) ... )( ... 'bc', ... set( ... 'a')), ... 'fg', ... ':<>') ('de', ['bc', {'a'}], 'fg', ':<>')
- hissp.macros._macro_.QzLSQB_QzHASH_(lookup, items='')#
[#
âsubscriptâ Injection. Pythonâs subscription operator.Interpret the lookup as Python code prepended with a
[
. Primarily used for Pythonâs slice notation, but unrestricted.#> [##1][::2] '(foo bar) >>> (lambda _Qznxnvf5z5__items: (_Qznxnvf5z5__items[1][::2]))( ... ('foo', ... 'bar',)) 'br'
Unary compatible with
->
and&#
.#> (-> '(foo bar) [#1] .upper [#::2]) >>> # QzH_QzGT_ ... (lambda _Qznxnvf5z5__items: (_Qznxnvf5z5__items[::2]))( ... (lambda _Qznxnvf5z5__items: (_Qznxnvf5z5__items[1]))( ... ('foo', ... 'bar',), ... ).upper(), ... ) 'BR' #> (.join "" (map &#[#1] '(abc xyz |123|))) >>> ('').join( ... map( ... __import__('functools').partial( ... (lambda _Qznxnvf5z5__items: (_Qznxnvf5z5__items[1])), ... ), ... ('abc', ... 'xyz', ... '123',))) 'by2'
See also:
!#
,->
,slice
,Subscriptions
,Slicings
.
- hissp.macros._macro_.QzLT_QzHASH_(comment)#
<#
âcomment stringâ tag.Converts a block of line comments to a raw string. Roughly equivalent to
'hissp.reader..Comment.contents#
.#> <#;You won't have to #..;; escape the "quotes". #.. >>> 'You won\'t have to\nescape the "quotes".' 'You won\'t have to\nescape the "quotes".'
See also:
triple-quoted string
,hissp.reader.Comment
.
- hissp.macros._macro_.QzPCENT_(*kvs)#
%
âdict ofâ. Mnemonic:dict
of pairs (%).Key-value pairs are implied by position. A
:**
mapping-unpacks the next argument.#> (% 1 2 :** (dict : x 3 y 4) 5 6) ; Dict, with mapping unpacking. >>> # QzPCENT_ ... (lambda x0, x1, x3, x4, x5: {x0:x1,**x3,x4:x5})( ... (1), ... (2), ... dict( ... x=(3), ... y=(4)), ... (5), ... (6)) {1: 2, 'x': 3, 'y': 4, 5: 6} #> (%) >>> # QzPCENT_ ... {} {}
See also:
@
,#
,operator.mod
.
- hissp.macros._macro_.QzSOL_QzHASH_(f)#
/#
âreduce byâ Wrap a binary function as a variadic via reduce.#> (/#operator..add 1 2 3 4) >>> (lambda *_Qztkr22wce__xs: ... __import__('functools').reduce( ... __import__('operator').add, ... _Qztkr22wce__xs) ... )( ... (1), ... (2), ... (3), ... (4)) 10
- hissp.macros._macro_.QzSOL_XYQzHASH_(expr)#
/XY#
âreduce X Yâ Anaphoric.Make
expr
a reducing function with parameters X Y. The resulting function is a partial application offunctools.reduce
.#> /XY#(op#add Y X) >>> __import__('functools').partial( ... __import__('functools').reduce, ... (lambda X, Y: ... __import__('operator').add( ... Y, ... X) ... )) functools.partial(<built-in function reduce>, <function <lambda> at 0x...>) #> (_ 'ABCD) >>> _( ... 'ABCD') 'DCBA'
- hissp.macros._macro_.XQzHASH_(expr)#
X#
Anaphoric. Makeexpr
an anonymous function with parameter X.Examples:
Convert macro to function.
#> (list (map X#(@ X) "abc")) ; en#list would also work here. >>> list( ... map( ... (lambda X: ... # QzAT_ ... (lambda *xs: [*xs])( ... X) ... ), ... ('abc'))) [['a'], ['b'], ['c']]
Compact function definition using Python operators.
#> (define teen? X#|13<=X<20|) >>> # define ... __import__('builtins').globals().update( ... teenQzQUERY_=(lambda X: 13<=X<20)) #> (teen? 12.5) >>> teenQzQUERY_( ... (12.5)) False #> (teen? 19.5) >>> teenQzQUERY_( ... (19.5)) True
Get an attribute without calling it.
#> (X#X.upper "shout") >>> (lambda X: X.upper)( ... ('shout')) <built-in method upper of str object at ...> #> (_) >>> _() 'SHOUT' #> (define class-name X#X.__class__.__name__) ; Attributes chain. >>> # define ... __import__('builtins').globals().update( ... classQzH_name=(lambda X: X.__class__.__name__)) #> (class-name object) >>> classQzH_name( ... object) 'type' #> (class-name "foo") >>> classQzH_name( ... ('foo')) 'str'
- hissp.macros._macro_.XYQzHASH_(expr)#
XY#
Anaphoric. Makeexpr
an anonymous function with parameters X Y.#> (functools..reduce XY#(op#concat Y X) 'abcd) >>> __import__('functools').reduce( ... (lambda X, Y: ... __import__('operator').concat( ... Y, ... X) ... ), ... 'abcd') 'dcba'
- hissp.macros._macro_.XYZQzHASH_(expr)#
XYZ#
Anaphoric. Makeexpr
an anonymous function with parameters X Y Z.#> (XYZ#|X*Y == Z| : X math..pi Y 2 Z math..tau) >>> (lambda X, Y, Z: X*Y == Z)( ... X=__import__('math').pi, ... Y=(2), ... Z=__import__('math').tau) True
- hissp.macros._macro_.XYZWQzHASH_(expr)#
XYZW#
Anaphoric. Makeexpr
an anonymous function with parameters X Y Z W.#> (XYZW#|X[Y:Z:W]| "QuaoblcldefHg" -2 1 -2) >>> (lambda X, Y, Z, W: X[Y:Z:W])( ... ('QuaoblcldefHg'), ... (-2), ... (1), ... (-2)) 'Hello'
- hissp.macros._macro_.alias(abbreviation, qualifier)#
Defines a
tag
abbreviation of aqualifier
.#> (hissp.._macro_.alias H hissp.) >>> # hissp.._macro_.alias ... # hissp.macros.._macro_.defmacro ... __import__('builtins').setattr( ... __import__('builtins').globals().get( ... ('_macro_')), ... 'HQzHASH_', ... # hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzwxh432ki__lambda=(lambda _Qzrtjqfxk2__attr, /, *_Qzrtjqfxk2__args, **_Qzrtjqfxk2__kwargs: ... # hissp.macros.._macro_.let ... ( ... lambda _Qzrtjqfxk2__attr=# hissp.macros.._macro_.ifQzH_else ... (lambda b, c, a: c()if b else a())( ... __import__('hissp').is_control( ... _Qzrtjqfxk2__attr), ... (lambda : ... ('_macro_.{}{}').format( ... __import__('hissp').munge( ... _Qzrtjqfxk2__attr.removeprefix( ... ':')), ... # hissp.macros.._macro_.ifQzH_else ... (lambda b, c, a: c()if b else a())( ... # hissp.macros.._macro_.ifQzH_else ... (lambda b, c, a: c()if b else a())( ... _Qzrtjqfxk2__args, ... (lambda : ':or'), ... (lambda : _Qzrtjqfxk2__kwargs)), ... (lambda : 'QzHASH_'), ... (lambda : ('')))) ... ), ... (lambda : _Qzrtjqfxk2__attr)): ... # hissp.macros.._macro_.ifQzH_else ... (lambda b, c, a: c()if b else a())( ... # hissp.macros.._macro_.ifQzH_else ... (lambda b, c, a: c()if b else a())( ... _Qzrtjqfxk2__args, ... (lambda : ':or'), ... (lambda : _Qzrtjqfxk2__kwargs)), ... (lambda : ... __import__('operator').attrgetter( ... _Qzrtjqfxk2__attr)( ... __import__('hissp'))( ... *_Qzrtjqfxk2__args, ... **_Qzrtjqfxk2__kwargs) ... ), ... (lambda : ... ('{}.{}').format( ... 'hissp.', ... _Qzrtjqfxk2__attr) ... )) ... )() ... ): ... (( ... *__import__('itertools').starmap( ... _Qzwxh432ki__lambda.__setattr__, ... __import__('builtins').dict( ... __doc__='Aliases ``hissp.`` as ``H#``.', ... __name__='HQzHASH_', ... __qualname__='_macro_.HQzHASH_', ... __code__=_Qzwxh432ki__lambda.__code__.replace( ... co_name='HQzHASH_')).items()), ... ), ... _Qzwxh432ki__lambda) [-1] ... )()) #> 'H#munge ; New tag prepends qualifier. >>> 'hissp..munge' 'hissp..munge' #> (H#munge "*") ; Normal function call. >>> __import__('hissp').munge( ... ('*')) 'QzSTAR_' #> 'H##munge|*| ; Read-time apply, like a fully-qualified tag. >>> 'QzSTAR_' 'QzSTAR_' #> 'H#:let-from ; control word inserts _macro_. Still munges. >>> 'hissp.._macro_.letQzH_from' 'hissp.._macro_.letQzH_from' #> (H#:let-from ab "AB" b) ; Macro form. >>> # hissp.._macro_.letQzH_from ... (lambda a, b: b)( ... *('AB')) 'B' #> H#|:b#| ;b# tag's callable. Note #. >>> __import__('hissp')._macro_.bQzHASH_ <function _macro_.bQzHASH_ at ...> #> (H#:b\#"b# at compile time") ; Macro form. :b\# == |:b#| >>> # hissp.._macro_.bQzHASH_ ... b'b# at compile time' b'b# at compile time' #> hissp.._macro_.b#"Fully-qualified b# at read time." ; \# implied. >>> b'Fully-qualified b# at read time.' b'Fully-qualified b# at read time.' #> H##:b"Read-time b# via alias." ; \# implied. >>> b'Read-time b# via alias.' b'Read-time b# via alias.' #> H###:@ ns=math. name='tau ; Kwargs also work. >>> __import__('operator').attrgetter( ... 'tau')( ... __import__('math')) 6.283185307179586
The bundled
op#
andi#
tags are aliases foroperator
anditertools
, respectively.See also:
prelude
,attach
,hissp.alias
.
- hissp.macros._macro_.ands(*exprs)#
Variadic shortcutting logical AND.
Returns the first false value, otherwise the last value. There is an implicit initial value of
True
.#> (ands True True False) ; and finds the False >>> # ands ... (lambda x0, x1, x2: x0 and x1()and x2())( ... True, ... (lambda : True), ... (lambda : False)) False #> (ands False (print 'oops)) ; Shortcutting. >>> # ands ... (lambda x0, x1: x0 and x1())( ... False, ... (lambda : ... print( ... 'oops') ... )) False #> (ands True 42) >>> # ands ... (lambda x0, x1: x0 and x1())( ... True, ... (lambda : (42))) 42 #> (ands) >>> # ands ... True True #> (ands 42) >>> # ands ... (42) 42
See also:
ors
,Boolean operations
,all
,when
.
- hissp.macros._macro_.anyQzH_map(variable, xs, *body)#
any-map
imperative iteratorfor
loop.Bind the variable and evaluate the body for each
x
fromxs
until any result is true (and returnTrue
), or untilxs
is exhausted (and returnFalse
).#> (any-map index (range 1 11) ;Imperative loop with break. #.. (print index : end :) #.. (not (op#mod index 7))) >>> # anyQzH_map ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda index: ... (print( ... index, ... end=':'), ... not( ... __import__('operator').mod( ... index, ... (7)))) [-1] ... ), ... range( ... (1), ... (11)))) 1:2:3:4:5:6:7:True
See also:
any
,map
,any*map
,The for statement
,The break statement
,functools.reduce
.
- hissp.macros._macro_.anyQzSTAR_map(variables, xss, *body)#
any*map
âany star mapâ imperative iteratorfor
loop & unpack.Bind each
x
to a variable and evaluate the body for eachxs
fromxss
until any result is true (and returnTrue
), or untilxss
is exhausted (and returnFalse
).#> (any*map (i c) (enumerate 'abc 1) ; As any-map, but with starmap. #.. (print (op#mul i c))) >>> # anyQzSTAR_map ... __import__('builtins').any( ... __import__('itertools').starmap( ... (lambda i, c: ... print( ... __import__('operator').mul( ... i, ... c)) ... ), ... enumerate( ... 'abc', ... (1)))) a bb ccc False
See also:
itertools.starmap
,any-map
,loop-from
,let*from
,my#
.
- hissp.macros._macro_.assure(expr, predicate, *args)#
Anaphoric. Raises
AssertionError
unless
(-> expr predicate)
.As
avow
, but expansion is simplyexpr
when__debug__
is off:$ python -Om hissp -c "(print (assure 0 bool))" 0 $ lissp -c "(print (assure 0 bool))" Hissp abort! Traceback (most recent call last): ... AssertionError
Note that for pre-compiled code, itâs the
__debug__
state at compile time, not at run time, that determines if assure assertions are turned on.For internal integrity checks, prefer
avow
toassure
, unless profiling indicates the check is unacceptably expensive in production, and the risk of not checking is acceptable; assume__debug__
will later be turned off.Also useful at the top level for quick unit tests in smaller projects, because they can be turned off. Larger projects may be better off with
unittest
and separated test modules, which need not be distributed and likely produce better error messages.#> (assure 7 (X#|X%2 == 0|) #.. it "That's odd.") >>> # assure ... # hissp.macros.._macro_.avow ... # hissp.macros.._macro_.let ... (lambda it=(7): ... (# hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... # hissp.macros.._macro_.QzH_QzGT_ ... (lambda X: X%2 == 0)( ... it), ... (lambda : ... # hissp.macros.._macro_.throw ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... __import__('builtins').AssertionError( ... it, ... ("That's odd."))) ... )), ... it) [-1] ... )() Traceback (most recent call last): ... AssertionError: (7, "That's odd.")
See also:
The assert statement
.
- hissp.macros._macro_.attach(target, *args)#
Attaches the named variables to the target as attributes.
Positional arguments must be identifiers. The identifier name becomes the attribute name. Names after the
:
are identifier-value pairs. Returns the target.#> (attach (types..SimpleNamespace) _macro_.attach : a 1 b 'Hi) >>> # attach ... # hissp.macros.._macro_.let ... (lambda _Qzwg5wn73w__target=__import__('types').SimpleNamespace(): ... (__import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'attach', ... _macro_.attach), ... __import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'a', ... (1)), ... __import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'b', ... 'Hi'), ... _Qzwg5wn73w__target) [-1] ... )() namespace(attach=<function _macro_.attach at 0x...>, a=1, b='Hi')
- hissp.macros._macro_.avow(expr, predicate, *args)#
Anaphoric. Raises
AssertionError
unless
(-> expr predicate)
.Additional arguments are evaluated in a context where
it
refers to the result ofexpr
. These (if any) are passed to theAssertionError
. Evaluates to the result ofexpr
.Assertions document assumptions that should never be false; only raise
AssertionError
s to fail fast when there is a bug in your code violating one, which can never happen if the code was written correctly. Though implemented as exceptions in Python, they should almost never be caught, except (perhaps) by a supervising system (such as aREPL
) capable of dealing with broken subsystems. They are not to be used like normal exceptions to handle expected cases.#> (avow 7 (X#|X%2 == 0|) #.. it "That's odd.") >>> # avow ... # hissp.macros.._macro_.let ... (lambda it=(7): ... (# hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... # hissp.macros.._macro_.QzH_QzGT_ ... (lambda X: X%2 == 0)( ... it), ... (lambda : ... # hissp.macros.._macro_.throw ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... __import__('builtins').AssertionError( ... it, ... ("That's odd."))) ... )), ... it) [-1] ... )() Traceback (most recent call last): ... AssertionError: (7, "That's odd.")
See also:
The assert statement
,assure
,throw
.
- hissp.macros._macro_.bQzHASH_(string)#
b#
âbytestringâ bytes literal tagConverts a
Hissp string
tobytes
.#> b#"bytes #..with\nnewlines" >>> b'bytes\nwith\nnewlines' b'bytes\nwith\nnewlines' #> b#'bytes! ; Note the '. Beware munging. >>> b'bytesQzBANG_' b'bytesQzBANG_' #> b#<# #..;; Bytes, #..;; newlines, \46 escapes! #.. >>> b'Bytes,\nnewlines, & escapes!' b'Bytes,\nnewlines, & escapes!'
See also:
B#
,hissp.reader.is_hissp_string
.
- hissp.macros._macro_.binding(pairs, *body)#
Runs body in a new
contextvars.Context
, with additional bindings.#> (defvar *greeting*) >>> # defvar ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'QzSTAR_greetingQzSTAR_'), ... (lambda : ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... QzSTAR_greetingQzSTAR_=__import__('contextvars').ContextVar( ... '*greeting*')) ... )) #> *greeting* >>> QzSTAR_greetingQzSTAR_ <ContextVar name='*greeting*' at 0x...> #> (defvar *greeted* "World!") >>> # defvar ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'QzSTAR_greetedQzSTAR_'), ... (lambda : ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... QzSTAR_greetedQzSTAR_=__import__('contextvars').ContextVar( ... '*greeted*', ... default=('World!'))) ... )) #> *greeted* >>> QzSTAR_greetedQzSTAR_ <ContextVar name='*greeted*' default='World!' at 0x...> #> (defun greet : (print (.get *greeting* "Hello,") (.get *greeted*))) >>> # defun ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... greet=# hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzan3nwcb3__lambda=(lambda : ... print( ... QzSTAR_greetingQzSTAR_.get( ... ('Hello,')), ... QzSTAR_greetedQzSTAR_.get()) ... ): ... (( ... *__import__('itertools').starmap( ... _Qzan3nwcb3__lambda.__setattr__, ... __import__('builtins').dict( ... __name__='greet', ... __qualname__='greet', ... __code__=_Qzan3nwcb3__lambda.__code__.replace( ... co_name='greet')).items()), ... ), ... _Qzan3nwcb3__lambda) [-1] ... )()) #> (greet) >>> greet() Hello, World! #> (binding (*greeting* "Goodbye," #.. *greeted* "all!") #.. (greet)) >>> # binding ... __import__('contextvars').copy_context().run( ... (lambda : ... (QzSTAR_greetingQzSTAR_.set( ... ('Goodbye,')), ... QzSTAR_greetedQzSTAR_.set( ... ('all!')), ... greet()) [-1] ... )) Goodbye, all! #> (greet) >>> greet() Hello, World!
See also:
defvar
.
- hissp.macros._macro_.bnQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
builtins.
asbn#
.
- hissp.macros._macro_.case(key, default, *pairs)#
Switch case macro.
Precomputes a lookup table (dict), so must switch on a hashable key. Target keys are not evaluated, so donât quote them; they must be known at compile time.
The default case is first and required. The remainder are implicitly paired by position.
#> (any-map x '(1 2 spam |42| :eggs) #.. (case x (print "default") #.. (0 2 |42|) (print "even") #.. (1 3 spam) (print "odd"))) >>> # anyQzH_map ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda x: ... # case ... ( ... (lambda : ... print( ... ('odd')) ... ), ... (lambda : ... print( ... ('even')) ... ), ... (lambda : ... print( ... ('default')) ... ), ... ).__getitem__( ... {1: 0, 3: 0, 'spam': 0, 0: 1, 2: 1, '42': 1}.get( ... x, ... (-1)))() ... ), ... ((1), ... (2), ... 'spam', ... '42', ... ':eggs',))) odd even odd even default False
See also:
cond
.
- hissp.macros._macro_.chainQzHASH_(xss)#
chain#
Abbreviation foritertools.chain.from_iterable
.
- hissp.macros._macro_.colQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
collections.
ascol#
.
- hissp.macros._macro_.cond(*pairs)#
Multiple condition branching.
Pairs are implied by position. Default is
()
. Use something always truthy to change it, like:else
orTrue
. For example:#> (any-map x (@ -0.6 -0.0 42.0 math..nan) #.. (cond (op#lt x 0) (print :Negative) ;if-else cascade #.. (op#eq x 0) (print :Zero) #.. (op#gt x 0) (print :Positive) #.. :else (print :Not-a-Number))) >>> # anyQzH_map ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda x: ... # cond ... (lambda x0, x1, x2, x3, x4, x5, x6, x7: ... x1() if x0 ... else x3() if x2() ... else x5() if x4() ... else x7() if x6() ... else () ... )( ... __import__('operator').lt( ... x, ... (0)), ... (lambda : ... print( ... ':Negative') ... ), ... (lambda : ... __import__('operator').eq( ... x, ... (0)) ... ), ... (lambda : ... print( ... ':Zero') ... ), ... (lambda : ... __import__('operator').gt( ... x, ... (0)) ... ), ... (lambda : ... print( ... ':Positive') ... ), ... (lambda : ':else'), ... (lambda : ... print( ... ':Not-a-Number') ... )) ... ), ... # QzAT_ ... (lambda *xs: [*xs])( ... (-0.6), ... (-0.0), ... (42.0), ... __import__('math').nan))) :Negative :Zero :Positive :Not-a-Number False
See also:
if-else
,case
,any-map
,The if statement
.
- hissp.macros._macro_.cxvQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
contextvars.
ascxv#
.
- hissp.macros._macro_.define(qualname, value)#
Assigns an attribute the value.
The qualname may be a
fully-qualified identifier
or start from a name in scope. Assigns an attribute of the current module (a global) if thereâs noqualifier
.#> (define SPAM 'tomato) >>> # define ... __import__('builtins').globals().update( ... SPAM='tomato') #> SPAM >>> SPAM 'tomato'
See also:
globals
,dict.update
,setattr
,defonce
,Assignment statements
,The global statement
.
- hissp.macros._macro_.defmacro(name, parameters, *body)#
Creates a new
macro function
for the current module.If thereâs no local
_macro_
namespace (at compile time), adds code to create one usingtypes.SimpleNamespace
(at runtime), if itâs still not there. If thereâs a docstring, stores it as the new lambdaâs__doc__
. Adds the_macro_
prefix to the lambdaâs__qualname__
. Saves the lambda in_macro_
using the given attribute name.#> (defmacro p123 (sep) #.. <#;Prints 1 2 3 with the given separator #.. `(print 1 2 3 : sep ,sep)) >>> # defmacro ... __import__('builtins').setattr( ... __import__('builtins').globals().get( ... ('_macro_')), ... 'p123', ... # hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzwin5lyqx__lambda=(lambda sep: ... ( ... 'builtins..print', ... (1), ... (2), ... (3), ... ':', ... '__main__..sep', ... sep, ... ) ... ): ... (( ... *__import__('itertools').starmap( ... _Qzwin5lyqx__lambda.__setattr__, ... __import__('builtins').dict( ... __doc__='Prints 1 2 3 with the given separator', ... __name__='p123', ... __qualname__='_macro_.p123', ... __code__=_Qzwin5lyqx__lambda.__code__.replace( ... co_name='p123')).items()), ... ), ... _Qzwin5lyqx__lambda) [-1] ... )()) #> (p123 ::) >>> # p123 ... __import__('builtins').print( ... (1), ... (2), ... (3), ... sep='::') 1::2::3
- hissp.macros._macro_.defonce(qualname, value)#
Defines an attribute, unless it exists.
Like
define
, but wonât overwrite an existing attribute. Useful when sending the whole file to theREPL
repeatedly or when usingimportlib.reload
.#> (defonce CACHE (types..SimpleNamespace : x 1)) >>> # defonce ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'CACHE'), ... (lambda : ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... CACHE=__import__('types').SimpleNamespace( ... x=(1))) ... )) #> (setattr CACHE 'x 42) >>> setattr( ... CACHE, ... 'x', ... (42)) #> (defonce CACHE (progn (print 'not 'evaluated) #.. (types..SimpleNamespace : x 1))) >>> # defonce ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'CACHE'), ... (lambda : ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... CACHE=# progn ... (print( ... 'not', ... 'evaluated'), ... __import__('types').SimpleNamespace( ... x=(1))) [-1]) ... )) () #> CACHE ; The second defonce had no effect. >>> CACHE namespace(x=42)
See also:
deftypeonce
,hissp.refresh
.
- hissp.macros._macro_.deftupleonce(typename, *args)#
Defines a
collections.namedtuple
unless it exists.#> (deftupleonce Vec3D '(x y z) : defaults '(0 0 0)) >>> # deftupleonce ... # hissp.macros.._macro_.defonce ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'Vec3D'), ... (lambda : ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... Vec3D=__import__('collections').namedtuple( ... 'Vec3D', ... ('x', ... 'y', ... 'z',), ... defaults=((0), ... (0), ... (0),))) ... ))
Like
deftypeonce
, methods can be attached afterward. On reload, the existing class is modified, affecting all of its instances, including those created before the reload.#> (define offset (Vec3D : z 1 x 2)) >>> # define ... __import__('builtins').globals().update( ... offset=Vec3D( ... z=(1), ... x=(2))) #> (defun Vec3D.__add__ (self other) #.. (._make Vec3D (map op#add self other))) >>> # defun ... # hissp.macros.._macro_.define ... __import__('builtins').setattr( ... Vec3D, ... '__add__', ... # hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzz7drxadm__lambda=(lambda self, other: ... Vec3D._make( ... map( ... __import__('operator').add, ... self, ... other)) ... ): ... (( ... *__import__('itertools').starmap( ... _Qzz7drxadm__lambda.__setattr__, ... __import__('builtins').dict( ... __name__='__add__', ... __qualname__='Vec3D.__add__', ... __code__=_Qzz7drxadm__lambda.__code__.replace( ... co_name='__add__')).items()), ... ), ... _Qzz7drxadm__lambda) [-1] ... )()) #> (op#add offset offset) >>> __import__('operator').add( ... offset, ... offset) Vec3D(x=4, y=0, z=2) #> (op#add _ (Vec3D 10 20 30)) >>> __import__('operator').add( ... _, ... Vec3D( ... (10), ... (20), ... (30))) Vec3D(x=14, y=20, z=32)
- hissp.macros._macro_.deftypeonce(qualname, bases=(), *once_decorators)#
Defines a
type
(class
), unless it exists.Add class attributes afterward using
define
ordefun
, and class decorators above with:@##
or afterward usingzap@
. These run again on module reload, updating the existing class object, which can affect the behavior its instances defined before the reload.The
once_decorators
apply before any external ones, in the order written (first applies first), unless the type exists (not reapplied on reloads). Beware that type attributes defined afterward will not be available for theonce_decorators
to operate upon. A decorator can add attributes for subsequent decorators to operate upon, however, and a decorator may be a lambda defined in line. It is possible to add arbitrary attributes this way, but remember thatonce_decorators
donât run again on reloads, so changes here cannot simply be reloaded with the module the way attributes defined afterward can.#> (deftypeonce Point2D (tuple) #.. ;; Example of setting an attr with an internal decorator. #.. X#(attach X : __doc__ "Simple ordered pair.")) >>> # deftypeonce ... # hissp.macros.._macro_.defonce ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'Point2D'), ... (lambda : ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... Point2D=(lambda X: ... # attach ... # hissp.macros.._macro_.let ... (lambda _Qzvibdgdly__target=X: ... (__import__('builtins').setattr( ... _Qzvibdgdly__target, ... '__doc__', ... ('Simple ordered pair.')), ... _Qzvibdgdly__target) [-1] ... )() ... )( ... __import__('builtins').type( ... 'Point2D', ... ( ... tuple, ... ), ... {}))) ... )) #> Point2D.__doc__ >>> Point2D.__doc__ 'Simple ordered pair.' #> (define Point2D.__doc__ #.. "Attributes can also be defined afterwards.") >>> # define ... __import__('builtins').setattr( ... Point2D, ... '__doc__', ... ('Attributes can also be defined afterwards.')) #> Point2D.__doc__ >>> Point2D.__doc__ 'Attributes can also be defined afterwards.' #> (defun Point2D.__new__ (cls x y) #.. (.__new__ tuple cls `(,x ,y))) >>> # defun ... # hissp.macros.._macro_.define ... __import__('builtins').setattr( ... Point2D, ... '__new__', ... # hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzzygff6yw__lambda=(lambda cls, x, y: ... tuple.__new__( ... cls, ... ( ... x, ... y, ... )) ... ): ... (( ... *__import__('itertools').starmap( ... _Qzzygff6yw__lambda.__setattr__, ... __import__('builtins').dict( ... __name__='__new__', ... __qualname__='Point2D.__new__', ... __code__=_Qzzygff6yw__lambda.__code__.replace( ... co_name='__new__')).items()), ... ), ... _Qzzygff6yw__lambda) [-1] ... )()) #> (defun Point2D.__repr__ (self) #.. (.format "Point2D({!r}, {!r})" : :* self)) >>> # defun ... # hissp.macros.._macro_.define ... __import__('builtins').setattr( ... Point2D, ... '__repr__', ... # hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzhdg2exzl__lambda=(lambda self: ... ('Point2D({!r}, {!r})').format( ... *self) ... ): ... (( ... *__import__('itertools').starmap( ... _Qzhdg2exzl__lambda.__setattr__, ... __import__('builtins').dict( ... __name__='__repr__', ... __qualname__='Point2D.__repr__', ... __code__=_Qzhdg2exzl__lambda.__code__.replace( ... co_name='__repr__')).items()), ... ), ... _Qzhdg2exzl__lambda) [-1] ... )()) #> (Point2D 1 2) >>> Point2D( ... (1), ... (2)) Point2D(1, 2)
Also supports keyword arguments in the bases tuple for
object.__init_subclass__
. Separate with a:
.#> :@##classmethod #..(defun Point2D.__init_subclass__ (cls :/ : :** kwargs) #.. "Just displays inputs" #.. (print kwargs)) >>> # hissp.macros.._macro_.define ... __import__('builtins').setattr( ... Point2D, ... '__init_subclass__', ... # hissp.macros.._macro_.progn ... (# defun ... # hissp.macros.._macro_.define ... __import__('builtins').setattr( ... Point2D, ... '__init_subclass__', ... # hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzujblvbnr__lambda=(lambda cls, /, **kwargs: ... print( ... kwargs) ... ): ... (( ... *__import__('itertools').starmap( ... _Qzujblvbnr__lambda.__setattr__, ... __import__('builtins').dict( ... __doc__=('Just displays inputs'), ... __name__='__init_subclass__', ... __qualname__='Point2D.__init_subclass__', ... __code__=_Qzujblvbnr__lambda.__code__.replace( ... co_name='__init_subclass__')).items()), ... ), ... _Qzujblvbnr__lambda) [-1] ... )()), ... classmethod( ... Point2D.__init_subclass__)) [-1]) #> (deftypeonce ASubclass (Point2D : a 1 b 2)) >>> # deftypeonce ... # hissp.macros.._macro_.defonce ... # hissp.macros.._macro_.unless ... (lambda b, a: ()if b else a())( ... __import__('operator').contains( ... __import__('builtins').globals(), ... 'ASubclass'), ... (lambda : ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... ASubclass=__import__('builtins').type( ... 'ASubclass', ... ( ... Point2D, ... ), ... {}, ... a=(1), ... b=(2))) ... )) {'a': 1, 'b': 2}
See also:
attach
,types.new_class
,defonce
.
- hissp.macros._macro_.defun(qualname, params, *body)#
define
afun
with the same name.See
deftypeonce
for how to define methods.See also:
Function definitions
,define
,defmacro
,:@##
.
- hissp.macros._macro_.defvar(name, default=<object object>)#
Creates a
contextvars.ContextVar
, unless it exists.The default is optional, but cannot be altered once set, however, a new binding may be set for a
contextvars.Context
.Intended for use at the top level only, because Python currently has no way of deleting a
ContextVar
once it has been added to the currentContext
. (Although aContextVar
could be deleted from the globals and replaced with a new one with the same name and a different default value, the oldContextVar
will also be in theContext
.)See
binding
for usage examples.See also:
defonce
.
- hissp.macros._macro_.destructQzH_QzGT_(data, bindings, *body)#
destruct->
âdestruct arrowâ Destructuring bindings.Bindings are pairs of a transform expression with either a name or (recursively) another bindings expression. Each transformation expression is applied to the data via a thread-first (
->
). This setup allows a bindings form to mirror the data itâs destructuring:#> (% 10 1 'ns (types..SimpleNamespace : a-tuple '(a b c) spam 'eggs)) >>> # QzPCENT_ ... (lambda x0, x1, x2, x3: {x0:x1,x2:x3})( ... (10), ... (1), ... 'ns', ... __import__('types').SimpleNamespace( ... aQzH_tuple=('a', ... 'b', ... 'c',), ... spam='eggs')) {10: 1, 'ns': namespace(aQzH_tuple=('a', 'b', 'c'), spam='eggs')} #> (define nested-data _) >>> # define ... __import__('builtins').globals().update( ... nestedQzH_data=_) #> (destruct-> nested-data #.. (!#10 num !#'ns (@#'a-tuple (!#0 a !#1 b !#2 c) @#'spam spam)) #.. (locals)) >>> # destructQzH_QzGT_ ... # hissp.macros.._macro_.letQzH_from ... (lambda num, a, b, c, spam: locals())( ... *# hissp.macros.._macro_.let ... (lambda _Qzcti67hlh__data=nestedQzH_data: ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... (10))( ... _Qzcti67hlh__data, ... ), ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzcti67hlh__data=# hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... 'ns')( ... _Qzcti67hlh__data, ... ): ... ( ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzcti67hlh__data=# hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').attrgetter( ... 'aQzH_tuple')( ... _Qzcti67hlh__data, ... ): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... (0))( ... _Qzcti67hlh__data, ... ), ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... (1))( ... _Qzcti67hlh__data, ... ), ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... (2))( ... _Qzcti67hlh__data, ... ), ... ) ... )(), ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').attrgetter( ... 'spam')( ... _Qzcti67hlh__data, ... ), ... ) ... )(), ... ) ... )()) {'num': 1, 'a': 'a', 'b': 'b', 'c': 'c', 'spam': 'eggs'}
But it doesnât have to. Transforms need not be simple lookups:
#> (destruct-> nested-data #.. (!#'ns (ors ns ; The whole SimpleNamespace (progn works too). #.. (getattr 'missing "a default for missing") missing #.. @#'spam inner ; attribute lookup #.. @#'a-tuple ([#:-1] ab [#:] abc ; slices with overlaps #.. iter (next A list rest) ; iterator destructuring #.. ;; Composed transform, method calls, defaults. #.. (-> enumerate dict) ((.get 2 ()) two #.. (.get 3 ()) three) #.. ;; Throwaway names must be unique. (`$#_ always works). #.. iter (next _0 (next :b) B next _1 (next :d) D))) #.. (.get 'quux "default for quux") myquux) #.. (pprint..pp (locals))) >>> # destructQzH_QzGT_ ... # hissp.macros.._macro_.letQzH_from ... (lambda ns, missing, inner, ab, abc, A, rest, two, three, _0, B, _1, D, myquux: ... __import__('pprint').pp( ... locals()) ... )( ... *# hissp.macros.._macro_.let ... (lambda _Qzcti67hlh__data=nestedQzH_data: ... ( ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzcti67hlh__data=# hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... 'ns')( ... _Qzcti67hlh__data, ... ): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... # ors ... _Qzcti67hlh__data, ... # hissp.macros.._macro_.QzH_QzGT_ ... getattr( ... _Qzcti67hlh__data, ... 'missing', ... ('a default for missing')), ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').attrgetter( ... 'spam')( ... _Qzcti67hlh__data, ... ), ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzcti67hlh__data=# hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').attrgetter( ... 'aQzH_tuple')( ... _Qzcti67hlh__data, ... ): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... (lambda _Qzuah3zizj__items: (_Qzuah3zizj__items[:-1]))( ... _Qzcti67hlh__data, ... ), ... # hissp.macros.._macro_.QzH_QzGT_ ... (lambda _Qzuah3zizj__items: (_Qzuah3zizj__items[:]))( ... _Qzcti67hlh__data, ... ), ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzcti67hlh__data=# hissp.macros.._macro_.QzH_QzGT_ ... iter( ... _Qzcti67hlh__data): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... next( ... _Qzcti67hlh__data), ... # hissp.macros.._macro_.QzH_QzGT_ ... list( ... _Qzcti67hlh__data), ... ) ... )(), ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzcti67hlh__data=# hissp.macros.._macro_.QzH_QzGT_ ... # QzH_QzGT_ ... dict( ... enumerate( ... _Qzcti67hlh__data)): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... _Qzcti67hlh__data.get( ... (2), ... ()), ... # hissp.macros.._macro_.QzH_QzGT_ ... _Qzcti67hlh__data.get( ... (3), ... ()), ... ) ... )(), ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzcti67hlh__data=# hissp.macros.._macro_.QzH_QzGT_ ... iter( ... _Qzcti67hlh__data): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... next( ... _Qzcti67hlh__data), ... # hissp.macros.._macro_.QzH_QzGT_ ... next( ... _Qzcti67hlh__data, ... ':b'), ... # hissp.macros.._macro_.QzH_QzGT_ ... next( ... _Qzcti67hlh__data), ... # hissp.macros.._macro_.QzH_QzGT_ ... next( ... _Qzcti67hlh__data, ... ':d'), ... ) ... )(), ... ) ... )(), ... ) ... )(), ... # hissp.macros.._macro_.QzH_QzGT_ ... _Qzcti67hlh__data.get( ... 'quux', ... ('default for quux')), ... ) ... )()) {'ns': namespace(aQzH_tuple=('a', 'b', 'c'), spam='eggs'), 'missing': 'a default for missing', 'inner': 'eggs', 'ab': ('a', 'b'), 'abc': ('a', 'b', 'c'), 'A': 'a', 'rest': ['b', 'c'], 'two': 'c', 'three': (), '_0': 'a', 'B': 'b', '_1': 'c', 'D': ':d', 'myquux': 'default for quux'}
- hissp.macros._macro_.doto(self, *invocations)#
Configure an object.
Calls multiple âmethodsâ on one âselfâ.
Evaluates the given
self
, then injects it as the first argument to a sequence of invocations. Returnsself
.#> (doto (list) #.. (.extend 'bar) #.. .sort #.. (.append 'foo)) >>> # doto ... (lambda _Qzkiumbhnz__self=list(): ... (_Qzkiumbhnz__self.extend( ... 'bar'), ... _Qzkiumbhnz__self.sort(), ... _Qzkiumbhnz__self.append( ... 'foo'), ... _Qzkiumbhnz__self) [-1] ... )() ['a', 'b', 'r', 'foo']
- hissp.macros._macro_.dtQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
datetime.
asdt#
.
- hissp.macros._macro_.enQzHASH_(f)#
en#
tag. Wrap a function applicable to a tuple as a function of its elements.#> (en#list 1 2 3) >>> (lambda *_Qz6rfwttvx__xs: ... list( ... _Qz6rfwttvx__xs) ... )( ... (1), ... (2), ... (3)) [1, 2, 3] #> (en#.extend _ 4 5 6) ; Methods too. #.. >>> (lambda _Qz6rfwttvx__self, *_Qz6rfwttvx__xs: ... _Qz6rfwttvx__self.extend( ... _Qz6rfwttvx__xs) ... )( ... _, ... (4), ... (5), ... (6)) #> _ >>> _ [1, 2, 3, 4, 5, 6] #> (define enjoin en#X#(.join "" (map str X))) >>> # define ... __import__('builtins').globals().update( ... enjoin=(lambda *_Qz6rfwttvx__xs: ... (lambda X: ... ('').join( ... map( ... str, ... X)) ... )( ... _Qz6rfwttvx__xs) ... )) #> (enjoin "Sum: "(op#add 2 3)". Product: "(op#mul 2 3)".") >>> enjoin( ... ('Sum: '), ... __import__('operator').add( ... (2), ... (3)), ... ('. Product: '), ... __import__('operator').mul( ... (2), ... (3)), ... ('.')) 'Sum: 5. Product: 6.'
There are no bundled tags for a quinary, senary, etc. but the
en#X#
variadic or a normal lambda form can be used instead.
- hissp.macros._macro_.fiQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
fileinput.
asfi#
.
- hissp.macros._macro_.ftQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
functools.
asft#
.
- hissp.macros._macro_.fun(qualname, params, maybeQzH_docstring=(), *body)#
A lambda enhanced with a
qualified name
and optionally a docstring.Hisspâs (and Pythonâs) lambda syntax do not have docstrings. Named lambdas improve
REPL
transparency and error messages, at the cost of some configuration overhead to set the name in the three places Python requires.Used by
defmacro
anddefun
. Not recommended for otherwise anonymous functions due to the additional overhead.
- hissp.macros._macro_.hshQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
hashlib.
ashsh#
.
- hissp.macros._macro_.iQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
itertools.
asi#
.
- hissp.macros._macro_.ifQzH_else(test, consequent, alternate)#
if-else
Basic ternary branching construct.Like Pythonâs conditional expressions, the âelseâ clause is required.
#> (any-map c 'ab #.. (if-else (op#eq c 'b) ;ternary conditional #.. (print 'Yes) #.. (print 'No))) >>> # anyQzH_map ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda c: ... # ifQzH_else ... (lambda b, c, a: c()if b else a())( ... __import__('operator').eq( ... c, ... 'b'), ... (lambda : ... print( ... 'Yes') ... ), ... (lambda : ... print( ... 'No') ... )) ... ), ... 'ab')) No Yes False
See also:
when
,cond
,any-map
,Conditional expressions
.
- hissp.macros._macro_.impQzDOT_rQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
importlib.resources.
asimp.r#
.
- hissp.macros._macro_.impQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
importlib.
asimp#
.
- hissp.macros._macro_.instQzHASH_(date_string)#
inst#
instant tag.Abbreviation for
datetime.datetime.fromisoformat
, with ademunge
for symbols.#> inst#2024-10-07T11:30:07+00:00 >>> # datetime.datetime(2024, 10, 7, 11, 30, 7, tzinfo=datetime.timezone.utc) ... __import__('pickle').loads(b'cdatetime\ndatetime\n(c_codecs\nencode\n(V\x07\xe8\\u000a\x07\x0b\x1e\x07\\u0000\\u0000\\u0000\nVlatin1\ntRcdatetime\ntimezone\n(cdatetime\ntimedelta\n(I0\nI0\nI0\ntRtRtR.') datetime.datetime(2024, 10, 7, 11, 30, 7, tzinfo=datetime.timezone.utc)
See also:
uuid#
.
- hissp.macros._macro_.let(pairs, *body)#
Creates local variables. Pairs are implied by position.
Locals are not in scope until the body.
#> (let (x 'a ;Create locals. #.. y 'b) ;Any number of pairs. #.. (print x y) #.. (let (x 'x #.. y (op#concat x x)) ;Not in scope until body. #.. (print x y)) ;Outer variables shadowed. #.. (print x y)) ;Inner went out of scope. >>> # let ... ( ... lambda x='a', ... y='b': ... (print( ... x, ... y), ... # let ... ( ... lambda x='x', ... y=__import__('operator').concat( ... x, ... x): ... print( ... x, ... y) ... )(), ... print( ... x, ... y)) [-1] ... )() a b x aa a b
- hissp.macros._macro_.letQzH_from(names, iterable, *body)#
let-from
Create listed locals from iterable.#> (let-from (a b : :* cs) 'ABCDEFG #.. (print cs b a)) >>> # letQzH_from ... (lambda a, b, *cs: ... print( ... cs, ... b, ... a) ... )( ... *'ABCDEFG') ('C', 'D', 'E', 'F', 'G') B A
See also:
let
,let*from
,Assignment statements
.
- hissp.macros._macro_.letQzSTAR_from(pairs, *body)#
let*from
âlet star fromâ Nestedlet-from
.Can unpack nested iterables by using multiple stages.
#> (dict : A 'B C 'D) >>> dict( ... A='B', ... C='D') {'A': 'B', 'C': 'D'} #> (let*from ((ab cd) (.items _) ;Nested let-froms. #.. (a b) ab ;Unpacks first item ('A', 'B') #.. (c d) cd) ;Unpacks second item ('C', 'D') #.. (print a b c d)) >>> # letQzSTAR_from ... # hissp.macros.._macro_.letQzH_from ... (lambda ab, cd: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.letQzH_from ... (lambda a, b: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.letQzH_from ... (lambda c, d: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.progn ... print( ... a, ... b, ... c, ... d) ... )( ... *cd) ... )( ... *ab) ... )( ... *_.items()) A B C D #> (let*from ((ab cd) (.items _) ;Fewer stack frames. #.. (a b c d) `(,@ab ,@cd)) ;Leveraging ,@ splicing. #.. (print a b c d)) >>> # letQzSTAR_from ... # hissp.macros.._macro_.letQzH_from ... (lambda ab, cd: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.letQzH_from ... (lambda a, b, c, d: ... # hissp.macros..QzMaybe_.letQzSTAR_from ... # hissp.macros.._macro_.progn ... print( ... a, ... b, ... c, ... d) ... )( ... *( ... *ab, ... *cd, ... )) ... )( ... *_.items()) A B C D #> (let-from (a c b d) ; Didn't really need let*from this time. #.. `(,@(.keys _) ,@(.values _)) ; Not always this easy. #.. (print a b c d)) >>> # letQzH_from ... (lambda a, c, b, d: ... print( ... a, ... b, ... c, ... d) ... )( ... *( ... *_.keys(), ... *_.values(), ... )) A B C D
See also:
my#
,destruct->
.
- hissp.macros._macro_.loopQzH_from(syms, inits, *body)#
loop-from
Anaphoric. Loop/recur with trampoline.Set local values for the first loop with an iterable as
let-from
.Creates a stack to schedule future loops. Call the
recur-from
anaphor with an iterable of values for the locals to push another loop to the schedule. Call withNone
to abort any remaining schedule.Returns the value of the final loop.
#> (loop-from x '(3) ;Unpacks as let-from. #.. (when x #.. (print x) #.. (recur-from (@ (op#sub x 1))))) >>> # loopQzH_from ... # hissp.macros.._macro_.let ... ( ... lambda _Qzj54t3dhw__stack=# hissp.macros..QzMaybe_.QzAT_ ... (lambda *xs: [*xs])( ... (), ... None, ... ((3),)): ... # hissp.macros.._macro_.let ... (lambda recurQzH_from=_Qzj54t3dhw__stack.append: ... (# hissp.macros.._macro_.anyQzSTAR_map ... __import__('builtins').any( ... __import__('itertools').starmap( ... (lambda x: ... (_Qzj54t3dhw__stack.__setitem__( ... (0), ... # hissp.macros.._macro_.progn ... # when ... (lambda b, c: c()if b else())( ... x, ... (lambda : ... (print( ... x), ... recurQzH_from( ... # QzAT_ ... (lambda *xs: [*xs])( ... __import__('operator').sub( ... x, ... (1))))) [-1] ... ))), ... None) [-1] ... ), ... __import__('builtins').iter( ... _Qzj54t3dhw__stack.pop, ... None))), ... __import__('operator').itemgetter( ... (0))( ... _Qzj54t3dhw__stack)) [-1] ... )() ... )() 3 2 1 ()
See also:
any*map
, Ensue,The while statement
.
- hissp.macros._macro_.mix(*args)#
Injection. Compiles each arg to Python and concatenates the fragments.
Lissp features like munging and fully-qualified identifiers can be freely mixed with Python expressions like slicing, infix operators and list comprehensions by using
fragment token
s:#> (mix |[|%|+|(.lower %)| for |%| in |string..ascii_uppercase|[:10]]|) >>> # mix ... [QzPCENT_+QzPCENT_.lower() for QzPCENT_ in __import__('string').ascii_uppercase[:10]] ['Aa', 'Bb', 'Cc', 'Dd', 'Ee', 'Ff', 'Gg', 'Hh', 'Ii', 'Jj']
Beware that a
str atom
like|:|
is still acontrol word
, and like|foo.|
is still amodule handle
, even when made with afragment token
. However, Python allows whitespace in many areas where it is not conventional to do so, making fragments like| :|
or|foo .|
viable workarounds in such cases.
- hissp.macros._macro_.mkQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
unittest.mock.
asmk#
.
- hissp.macros._macro_.mpQzDOT_smQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
multiprocessing.shared_memory.
asmp.sm#
.
- hissp.macros._macro_.mpQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
multiprocessing.
asmp#
.
- hissp.macros._macro_.myQzHASH_(targets_or_scope, expr=None, scope=(), **kwargs)#
my#
Anaphoric. Injection.let
my
be a freshtypes.SimpleNamespace
in a lexical scope.Creates a local namespace for imperative-style (re)assignments.
Kwarg token
s in scope translate toset@
.Often combined with branching macros to reuse the results of an expression, with uses similar to Pythonâs âwalrusâ operator
:=
. Seepython-grammar:assignment_expression
.#> my#(print x=(op#add 1 1) my.x) >>> # hissp.macros.._macro_.let ... (lambda my=__import__('types').SimpleNamespace(): ... print( ... # hissp.macros.._macro_.setQzAT_ ... # hissp.macros.._macro_.let ... ( ... lambda _Qzwk5j5q64__value=__import__('operator').add( ... (1), ... (1)): ... (# hissp.macros.._macro_.define ... __import__('builtins').setattr( ... my, ... 'x', ... _Qzwk5j5q64__value), ... _Qzwk5j5q64__value) [-1] ... )(), ... my.x) ... )() 2 2 #> my#my ; Empty namespace shorthand. >>> # hissp.macros.._macro_.let ... (lambda my=__import__('types').SimpleNamespace(): my)() namespace() #> my##foo=2 my ; Initial content from read-time kwarg. >>> # hissp.macros.._macro_.let ... ( ... lambda my=__import__('types').SimpleNamespace( ... foo=(2)): ... my)() namespace(foo=2) #> my##outer=2 my###inner=1 bridge=my (@ my.bridge.outer my.inner) >>> # hissp.macros.._macro_.let ... ( ... lambda my=__import__('types').SimpleNamespace( ... outer=(2)): ... # hissp.macros.._macro_.let ... ( ... lambda my=__import__('types').SimpleNamespace( ... inner=(1), ... bridge=my): ... # QzAT_ ... (lambda *xs: [*xs])( ... my.bridge.outer, ... my.inner) ... )() ... )() [2, 1]
With at least two positional arguments, the first is an injected Python assignment target, and the second its value:
#> my### a,b,[c,*xs] '(1 2 |spam|) my ; Nested unpacking. >>> # hissp.macros.._macro_.let ... ( ... lambda my=__import__('types').SimpleNamespace( ... **# hissp.macros.._macro_.let ... ( ... lambda _Qze4jatheu__expr=((1), ... (2), ... 'spam',): ... [__import__('builtins').locals() ... for (a,b,[c,*xs]) ... in [_Qze4jatheu__expr]] [0] ... )()): ... (my.__dict__.pop( ... '_Qze4jatheu__expr', ... None), ... my.__dict__.pop( ... ('.0'), ... None), ... my) [-1] ... )() namespace(a=1, b=2, c='s', xs=['p', 'a', 'm'])
Use
zap@
for augmented assignments:#> my###a,b 'AB (@ (zap@ my.a iadd c='C) my) >>> # hissp.macros.._macro_.let ... ( ... lambda my=__import__('types').SimpleNamespace( ... **# hissp.macros.._macro_.let ... (lambda _Qzec6padpw__expr='AB': ... [__import__('builtins').locals() ... for (a,b) ... in [_Qzec6padpw__expr]] [0] ... )()): ... (my.__dict__.pop( ... '_Qzec6padpw__expr', ... None), ... my.__dict__.pop( ... ('.0'), ... None), ... # QzAT_ ... (lambda *xs: [*xs])( ... # zapQzAT_ ... # hissp.macros.._macro_.setQzAT_ ... # hissp.macros.._macro_.let ... ( ... lambda _Qzqfrecvdx__value=iadd( ... my.a, ... # hissp.macros.._macro_.setQzAT_ ... # hissp.macros.._macro_.let ... (lambda _Qzqfrecvdx__value='C': ... (# hissp.macros.._macro_.define ... __import__('builtins').setattr( ... my, ... 'c', ... _Qzqfrecvdx__value), ... _Qzqfrecvdx__value) [-1] ... )()): ... (# hissp.macros.._macro_.define ... __import__('builtins').setattr( ... my, ... 'a', ... _Qzqfrecvdx__value), ... _Qzqfrecvdx__value) [-1] ... )(), ... my)) [-1] ... )() ['AC', namespace(a='AC', b='B', c='C')]
Assignment targets need not be locals, so a scope argument is optional:
#> my## |globals()['spam'], spam.eggs| (|| my#my (list 'abcdefg) ||) >>> # hissp.macros.._macro_.let ... ( ... lambda my=__import__('types').SimpleNamespace( ... **# hissp.macros.._macro_.let ... ( ... lambda _Qze4jatheu__expr=( ... # hissp.macros.._macro_.let ... (lambda my=__import__('types').SimpleNamespace(): my)(), ... list( ... 'abcdefg'), ... ): ... [__import__('builtins').locals() ... for (globals()['spam'], spam.eggs) ... in [_Qze4jatheu__expr]] [0] ... )()): ... (my.__dict__.pop( ... '_Qze4jatheu__expr', ... None), ... my.__dict__.pop( ... ('.0'), ... None), ... ()) [-1] ... )() () #> my#### spam.eggs[2::2] 'XYZ tomato=spam my ; Assign a global's slice. >>> # hissp.macros.._macro_.let ... ( ... lambda my=__import__('types').SimpleNamespace( ... **# hissp.macros.._macro_.let ... (lambda _Qze4jatheu__expr='XYZ': ... [__import__('builtins').locals() ... for (spam.eggs[2::2]) ... in [_Qze4jatheu__expr]] [0] ... )(), ... tomato=spam): ... (my.__dict__.pop( ... '_Qze4jatheu__expr', ... None), ... my.__dict__.pop( ... ('.0'), ... None), ... my) [-1] ... )() namespace(tomato=namespace(eggs=['a', 'b', 'X', 'd', 'Y', 'f', 'Z']))
See also:
attach
,set[###
,destruct->
.
- hissp.macros._macro_.nilQzHASH_(x)#
nil#
evaluates asx or ()
. Adapter for ânil punningâ.
- hissp.macros._macro_.nspQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
inspect.
asnsp#
.
- hissp.macros._macro_.opQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
operator.
asop#
.
- hissp.macros._macro_.ors(*exprs)#
Variadic shortcutting logical OR.
Returns the first true value, otherwise the last value. There is an implicit initial value of
()
.#> (ors True (print 'oops)) ; Shortcutting. >>> # ors ... (lambda x0, x1: x0 or x1())( ... True, ... (lambda : ... print( ... 'oops') ... )) True #> (ors 42 False) >>> # ors ... (lambda x0, x1: x0 or x1())( ... (42), ... (lambda : False)) 42 #> (ors () False 0 1) ; or seeks the truth >>> # ors ... (lambda x0, x1, x2, x3: x0 or x1()or x2()or x3())( ... (), ... (lambda : False), ... (lambda : (0)), ... (lambda : (1))) 1 #> (ors False) >>> # ors ... False False #> (ors) >>> # ors ... () ()
See also:
ands
,bool
,Boolean operations
,any
.
- hissp.macros._macro_.plQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
pathlib.
aspl#
.
- hissp.macros._macro_.posQzHASH_(bindings)#
pos\#
âposition bindingsâdestruct->
helper shorthand. Destructures a sequence using each binding formâs position index.#> (destruct-> '(ABC XYZ) #.. (ors whole ors pos#(abc pos#(x y))) #.. (print whole abc x y)) >>> # destructQzH_QzGT_ ... # hissp.macros.._macro_.letQzH_from ... (lambda whole, abc, x, y: ... print( ... whole, ... abc, ... x, ... y) ... )( ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzzqguiyyn__data=('ABC', ... 'XYZ',): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... # ors ... _Qzzqguiyyn__data, ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzzqguiyyn__data=# hissp.macros.._macro_.QzH_QzGT_ ... # ors ... _Qzzqguiyyn__data: ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... (0))( ... _Qzzqguiyyn__data, ... ), ... *# hissp.macros.._macro_.let ... ( ... lambda _Qzzqguiyyn__data=# hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... (1))( ... _Qzzqguiyyn__data, ... ): ... ( ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... (0))( ... _Qzzqguiyyn__data, ... ), ... # hissp.macros.._macro_.QzH_QzGT_ ... __import__('operator').itemgetter( ... (1))( ... _Qzzqguiyyn__data, ... ), ... ) ... )(), ... ) ... )(), ... ) ... )()) ('ABC', 'XYZ') ABC X Y
- hissp.macros._macro_.prelude(env=('builtins..globals',))#
Hisspâs bundled micro prelude.
Brings Hissp up to a minimal standard of usability without adding any dependencies in the compiled output.
Mainly intended for single-file scripts that canât have dependencies, or similarly constrained environments (e.g., embedded,
readerless mode
). There, the first form should be(hissp.._macro_.prelude)
, which is also implied in$ lissp -c
commands. (See thehissp.prelude
shorthand for Lissp.)Larger projects with access to functional and macro libraries need not use this prelude at all.
The prelude has several effects:
Defines
engarde
, which calls a function with exception handler:def engarde(xs,h,f,/,*a,**kw): try:return f(*a,**kw) except xs as e:return h(e)
engarde
with handlers can stack above in a single tuple.See engarde examples below.
Defines
enter
, which calls a function with context manager:def enter(c,f,/,*a): with c as C:return f(*a,C)
enter
with context managers can stack above in a single tuple.See enter examples below.
Defines the
Ensue
class; trampolined continuation generators:class Ensue(__import__('collections.abc').abc.Generator): send=lambda s,v:s.g.send(v);throw=lambda s,*x:s.g.throw(*x);F=0;X=();Y=[] def __init__(s,p):s.p,s.g,s.n=p,s._(s),s.Y def _(s,k,v=None): while isinstance(s:=k,__class__) and not setattr(s,'sent',v): try:k,y=s.p(s),s.Y;v=(yield from y)if s.F or y is s.n else(yield y) except s.X as e:v=e return k
Ensue
takes a step function and returns a generator. The step function receives the previous Ensue step and must return the next one to continue. Returning a different type raises aStopIteration
with that object. Set theY
attribute on the current step to [Y]ield a value this step. Set theF
attribute to a true value to yield values [F]rom theY
iterable instead. Set theX
attribute to an e[X]ception class or tuple to catch any targeted exceptions on the next step. Each step keeps asent
attribute, which is the value sent to the generator this step, or the exception caught this step instead.See Ensue examples and enter examples below.
See also:
types.coroutine
,collections.abc.Generator
,loop-from
.Adds the bundled macros, but only if available (macros are typically only used at compile time), so its compiled expansion does not require Hissp to be installed. (This replaces
_macro_
if you already had one.):_macro_=__import__('types').SimpleNamespace() try: vars(_macro_).update(vars(__import__('hissp')._macro_)) except ModuleNotFoundError: pass
Prelude Usage#
The
REPL
has the bundled macros loaded by default, but not the prelude. Invoke(prelude)
to get the rest.#> (prelude) >>> # prelude ... __import__('builtins').exec( ... ('from itertools import *;from operator import *\n' ... 'def engarde(xs,h,f,/,*a,**kw):\n' ... ' try:return f(*a,**kw)\n' ... ' except xs as e:return h(e)\n' ... 'def enter(c,f,/,*a):\n' ... ' with c as C:return f(*a,C)\n' ... "class Ensue(__import__('collections.abc').abc.Generator):\n" ... ' send=lambda s,v:s.g.send(v);throw=lambda s,*x:s.g.throw(*x);F=0;X=();Y=[]\n' ... ' def __init__(s,p):s.p,s.g,s.n=p,s._(s),s.Y\n' ... ' def _(s,k,v=None):\n' ... " while isinstance(s:=k,__class__) and not setattr(s,'sent',v):\n" ... ' try:k,y=s.p(s),s.Y;v=(yield from y)if s.F or y is s.n else(yield y)\n' ... ' except s.X as e:v=e\n' ... ' return k\n' ... "_macro_=__import__('types').SimpleNamespace()\n" ... "try: vars(_macro_).update(vars(__import__('hissp')._macro_))\n" ... 'except ModuleNotFoundError: pass'), ... __import__('builtins').globals())
See also,
alias
.engarde examples#
#> (engarde `(,FloatingPointError ,ZeroDivisionError) ;two targets #.. (lambda e (print "Oops!") e) ;handler (returns exception) #.. truediv 6 0) ;calls it on your behalf >>> engarde( ... ( ... FloatingPointError, ... ZeroDivisionError, ... ), ... (lambda e: ... (print( ... ('Oops!')), ... e) [-1] ... ), ... truediv, ... (6), ... (0)) Oops! ZeroDivisionError('division by zero') #> (engarde ArithmeticError repr truediv 6 0) ;superclass target >>> engarde( ... ArithmeticError, ... repr, ... truediv, ... (6), ... (0)) "ZeroDivisionError('division by zero')" #> (engarde ArithmeticError repr truediv 6 2) ;returned answer >>> engarde( ... ArithmeticError, ... repr, ... truediv, ... (6), ... (2)) 3.0 #> (engarde Exception ;The stacked outer engarde #.. print #.. engarde ZeroDivisionError ; calls the inner. #.. (lambda e (print "It means what you want it to mean.")) #.. truediv "6" 0) ;Try variations. >>> engarde( ... Exception, ... print, ... engarde, ... ZeroDivisionError, ... (lambda e: ... print( ... ('It means what you want it to mean.')) ... ), ... truediv, ... ('6'), ... (0)) unsupported operand type(s) for /: 'str' and 'int' #> (engarde Exception #.. (lambda x x.__cause__) #.. (lambda : (throw-from Exception (Exception "msg")))) >>> engarde( ... Exception, ... (lambda x: x.__cause__), ... (lambda : ... # throwQzH_from ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... # hissp.macros.._macro_.let ... ( ... lambda _Qzzkusd5eu__G=(lambda _Qzzkusd5eu__x: ... # hissp.macros.._macro_.ifQzH_else ... (lambda b, c, a: c()if b else a())( ... __import__('builtins').isinstance( ... _Qzzkusd5eu__x, ... __import__('builtins').BaseException), ... (lambda : _Qzzkusd5eu__x), ... (lambda : _Qzzkusd5eu__x())) ... ): ... # hissp.macros.._macro_.attach ... # hissp.macros.._macro_.let ... ( ... lambda _Qzwawunnb6__target=_Qzzkusd5eu__G( ... Exception): ... (__import__('builtins').setattr( ... _Qzwawunnb6__target, ... '__cause__', ... _Qzzkusd5eu__G( ... Exception( ... ('msg')))), ... _Qzwawunnb6__target) [-1] ... )() ... )()) ... )) Exception('msg')
Ensue examples#
#> (.update (globals) #.. : fibonacci #.. (lambda (: a 1 b 1) #.. (Ensue (lambda (step) #.. (setattr step 'Y a) ;Y for yield. #.. (fibonacci b (add a b)))))) >>> globals().update( ... fibonacci=( ... lambda a=(1), ... b=(1): ... Ensue( ... (lambda step: ... (setattr( ... step, ... 'Y', ... a), ... fibonacci( ... b, ... add( ... a, ... b))) [-1] ... )) ... )) #> (list (islice (fibonacci) 7)) >>> list( ... islice( ... fibonacci(), ... (7))) [1, 1, 2, 3, 5, 8, 13] #> (.update (globals) ; Terminate by not returning an Ensue. #.. : my-range #.. (lambda in #.. (Ensue (lambda (step) #.. (when (lt i n) ;Acts like a while loop. #.. (setattr step 'Y i) #.. (my-range (add i 1) n)))))) ;Conditional recursion. #.. >>> globals().update( ... myQzH_range=(lambda i, n: ... Ensue( ... (lambda step: ... # when ... (lambda b, c: c()if b else())( ... lt( ... i, ... n), ... (lambda : ... (setattr( ... step, ... 'Y', ... i), ... myQzH_range( ... add( ... i, ... (1)), ... n)) [-1] ... )) ... )) ... )) #> (list (my-range 1 6)) >>> list( ... myQzH_range( ... (1), ... (6))) [1, 2, 3, 4, 5] #> (Ensue (lambda (step) #.. (attach step : #.. F True ; Set F for yield-From mode. #.. Y '(1 2 3 4 5)) #.. None)) >>> Ensue( ... (lambda step: ... (# attach ... # hissp.macros.._macro_.let ... (lambda _Qzwg5wn73w__target=step: ... (__import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'F', ... True), ... __import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'Y', ... ((1), ... (2), ... (3), ... (4), ... (5),)), ... _Qzwg5wn73w__target) [-1] ... )(), ... None) [-1] ... )) <...Ensue object at ...> #> (list _) >>> list( ... _) [1, 2, 3, 4, 5] #> (define recycle #.. (lambda (itr) #.. (Ensue (lambda (step) #.. ;; Implicit continuation; step is an Ensue. #.. (attach step : Y itr F 1))))) >>> # define ... __import__('builtins').globals().update( ... recycle=(lambda itr: ... Ensue( ... (lambda step: ... # attach ... # hissp.macros.._macro_.let ... (lambda _Qzwg5wn73w__target=step: ... (__import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'Y', ... itr), ... __import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'F', ... (1)), ... _Qzwg5wn73w__target) [-1] ... )() ... )) ... )) #> (-> '(1 2 3) recycle (islice 7) list) >>> # QzH_QzGT_ ... list( ... islice( ... recycle( ... ((1), ... (2), ... (3),)), ... (7))) [1, 2, 3, 1, 2, 3, 1] #> (.update (globals) #.. : echo #.. (Ensue (lambda (step) #.. (setattr step 'Y step.sent) #.. step))) >>> globals().update( ... echo=Ensue( ... (lambda step: ... (setattr( ... step, ... 'Y', ... step.sent), ... step) [-1] ... ))) #> (.send echo None) ; Always send a None first. Same as Python. >>> echo.send( ... None) #> (.send echo "Yodel!") ; Generators are two-way. >>> echo.send( ... ('Yodel!')) 'Yodel!' #> (.send echo 42) >>> echo.send( ... (42)) 42
enter examples#
#> :@##contextlib..contextmanager #..(defun wrap (msg) #.. (print "enter" msg) #.. (Ensue (lambda (step) #.. (setattr step 'Y msg) #.. (Ensue (lambda (step) #.. (print "exit" msg)))))) >>> # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... wrap=# hissp.macros.._macro_.progn ... (# defun ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... wrap=# hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qztl624wbs__lambda=(lambda msg: ... (print( ... ('enter'), ... msg), ... Ensue( ... (lambda step: ... (setattr( ... step, ... 'Y', ... msg), ... Ensue( ... (lambda step: ... print( ... ('exit'), ... msg) ... ))) [-1] ... ))) [-1] ... ): ... (( ... *__import__('itertools').starmap( ... _Qztl624wbs__lambda.__setattr__, ... __import__('builtins').dict( ... __name__='wrap', ... __qualname__='wrap', ... __code__=_Qztl624wbs__lambda.__code__.replace( ... co_name='wrap')).items()), ... ), ... _Qztl624wbs__lambda) [-1] ... )()), ... __import__('contextlib').contextmanager( ... wrap)) [-1]) #> (enter (wrap 'A) #.. (lambda a (print a))) >>> enter( ... wrap( ... 'A'), ... (lambda a: ... print( ... a) ... )) enter A A exit A #> (enter (wrap 'A) #.. enter (wrap 'B) #.. enter (wrap 'C) ; You can stack them. #.. (lambda abc (print a b c))) >>> enter( ... wrap( ... 'A'), ... enter, ... wrap( ... 'B'), ... enter, ... wrap( ... 'C'), ... (lambda a, b, c: ... print( ... a, ... b, ... c) ... )) enter A enter B enter C A B C exit C exit B exit A #> (define suppress-zde #.. (contextlib..contextmanager #.. (lambda : #.. (Ensue (lambda (step) #.. (attach step : #.. Y None #.. X ZeroDivisionError) ; X for eXcept (can be a tuple). #.. (Ensue (lambda (step) #.. (print "Caught a" step.sent)))))))) >>> # define ... __import__('builtins').globals().update( ... suppressQzH_zde=__import__('contextlib').contextmanager( ... (lambda : ... Ensue( ... (lambda step: ... (# attach ... # hissp.macros.._macro_.let ... (lambda _Qzwg5wn73w__target=step: ... (__import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'Y', ... None), ... __import__('builtins').setattr( ... _Qzwg5wn73w__target, ... 'X', ... ZeroDivisionError), ... _Qzwg5wn73w__target) [-1] ... )(), ... Ensue( ... (lambda step: ... print( ... ('Caught a'), ... step.sent) ... ))) [-1] ... )) ... ))) #> (enter (suppress-zde) #.. (lambda _ (truediv 1 0))) >>> enter( ... suppressQzH_zde(), ... (lambda _: ... truediv( ... (1), ... (0)) ... )) Caught a division by zero #> (enter (suppress-zde) ; No exception, so step.sent was .send() value. #.. (lambda _ (truediv 4 2))) >>> enter( ... suppressQzH_zde(), ... (lambda _: ... truediv( ... (4), ... (2)) ... )) Caught a None 2.0 #> (enter (suppress-zde) #.. (lambda _ (throw Exception))) >>> enter( ... suppressQzH_zde(), ... (lambda _: ... # throw ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... Exception) ... )) Traceback (most recent call last): ... Exception
- hissp.macros._macro_.prog1(expr1, *body)#
Evaluates sequentially (for side effects). Returns value of
expr1
.#> (print (prog1 0 ;Side effects in sequence. Eval to first. #.. (print 1) #.. (print 2))) >>> print( ... # prog1 ... # hissp.macros.._macro_.let ... (lambda _Qz46bj7iw6__value1=(0): ... (print( ... (1)), ... print( ... (2)), ... _Qz46bj7iw6__value1) [-1] ... )()) 1 2 0
Combine with
progn
for a value in the middle of the sequence:#> (prog1 ;Side effects in sequence. Eval to first. #.. (progn (print 1) ;Side effects in sequence. Eval to last. #.. 3) #.. (print 2)) >>> # prog1 ... # hissp.macros.._macro_.let ... ( ... lambda _Qz46bj7iw6__value1=# progn ... (print( ... (1)), ... (3)) [-1]: ... (print( ... (2)), ... _Qz46bj7iw6__value1) [-1] ... )() 1 2 3
See also:
doto
.
- hissp.macros._macro_.progn(*body)#
Evaluates each body expression in sequence (for side effects), resulting in the value of the last (or
()
if empty).#> (print (progn (print 1) ;Sequence for side effects, eval to last. #.. (print 2) #.. 3)) >>> print( ... # progn ... (print( ... (1)), ... print( ... (2)), ... (3)) [-1]) 1 2 3
See also:
prog1
,Expression statements
.
- hissp.macros._macro_.proxyQzHASH_(f)#
proxy#
wrapper to make a stored callable reloadable.For this to work, it should be applied to a lookup expression such as a global variable name or module attribute. This will be written into the wrapper body.
#> (defun greet () #.. (print "Hello, World!")) >>> # defun ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... greet=# hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzan3nwcb3__lambda=(lambda : ... print( ... ('Hello, World!')) ... ): ... (( ... *__import__('itertools').starmap( ... _Qzan3nwcb3__lambda.__setattr__, ... __import__('builtins').dict( ... __name__='greet', ... __qualname__='greet', ... __code__=_Qzan3nwcb3__lambda.__code__.replace( ... co_name='greet')).items()), ... ), ... _Qzan3nwcb3__lambda) [-1] ... )()) #> proxy#greet >>> __import__('functools').update_wrapper( ... (lambda *_Qzxd2las5y__args, **_Qzxd2las5y__kwargs: ... greet( ... *_Qzxd2las5y__args, ... **_Qzxd2las5y__kwargs) ... ), ... greet) <function greet at 0x...> #> (define greet-handlers (types..SimpleNamespace : direct greet proxied _)) >>> # define ... __import__('builtins').globals().update( ... greetQzH_handlers=__import__('types').SimpleNamespace( ... direct=greet, ... proxied=_))
Now suppose
greet
is reloaded with a new definition, butgreet-handlers
is not (perhaps due to being in separate modules or ifgreet-handlers
had useddefonce
):#> (defun greet () #.. (print "Wassup?")) >>> # defun ... # hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... greet=# hissp.macros.._macro_.fun ... # hissp.macros.._macro_.let ... ( ... lambda _Qzan3nwcb3__lambda=(lambda : ... print( ... ('Wassup?')) ... ): ... (( ... *__import__('itertools').starmap( ... _Qzan3nwcb3__lambda.__setattr__, ... __import__('builtins').dict( ... __name__='greet', ... __qualname__='greet', ... __code__=_Qzan3nwcb3__lambda.__code__.replace( ... co_name='greet')).items()), ... ), ... _Qzan3nwcb3__lambda) [-1] ... )()) #> (greet-handlers.direct) ; Still the original function object. >>> greetQzH_handlers.direct() Hello, World! #> (greet-handlers.proxied) ; Proxy does the lookup again. >>> greetQzH_handlers.proxied() Wassup?
- hissp.macros._macro_.sentinelQzHASH_(f)#
sentinel#
Anaphoric.Let
_sentinel
be a unique sentinel object in a lexical scope surroundingf
.
- hissp.macros._macro_.setQzAT_(qualname, value)#
set@
âsetatâ Assigns an attribute, returns the value.The namespace part of the
qualname
may be fully qualified or start from a name in scope. An empty namespace part sets an attribute of the current module (a global).Mnemonic: set @tribute.
#> (set@ eggs (set@ spam (types..SimpleNamespace))) ; define can't do this. >>> # setQzAT_ ... # hissp.macros.._macro_.let ... ( ... lambda _Qzqfrecvdx__value=# setQzAT_ ... # hissp.macros.._macro_.let ... (lambda _Qzqfrecvdx__value=__import__('types').SimpleNamespace(): ... (# hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... spam=_Qzqfrecvdx__value), ... _Qzqfrecvdx__value) [-1] ... )(): ... (# hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... eggs=_Qzqfrecvdx__value), ... _Qzqfrecvdx__value) [-1] ... )() namespace() #> (set@ spam.foo (types..SimpleNamespace)) >>> # setQzAT_ ... # hissp.macros.._macro_.let ... (lambda _Qzqfrecvdx__value=__import__('types').SimpleNamespace(): ... (# hissp.macros.._macro_.define ... __import__('builtins').setattr( ... spam, ... 'foo', ... _Qzqfrecvdx__value), ... _Qzqfrecvdx__value) [-1] ... )() namespace() #> (set@ spam.foo.bar 4) >>> # setQzAT_ ... # hissp.macros.._macro_.let ... (lambda _Qzqfrecvdx__value=(4): ... (# hissp.macros.._macro_.define ... __import__('builtins').setattr( ... spam.foo, ... 'bar', ... _Qzqfrecvdx__value), ... _Qzqfrecvdx__value) [-1] ... )() 4 #> spam >>> spam namespace(foo=namespace(bar=4))
- hissp.macros._macro_.setQzBANG_(items, key, value)#
set!
âsetbangâ Assigns an item, returns the value.Mnemonic: set !tem.
#> (define spam (dict)) >>> # define ... __import__('builtins').globals().update( ... spam=dict()) #> (set! spam 1 (set! spam 2 10)) ; setitem can't do this. #.. >>> # setQzBANG_ ... # hissp.macros.._macro_.let ... ( ... lambda _Qzwk5j5q64__value=# setQzBANG_ ... # hissp.macros.._macro_.let ... (lambda _Qzwk5j5q64__value=(10): ... (__import__('operator').setitem( ... spam, ... (2), ... _Qzwk5j5q64__value), ... _Qzwk5j5q64__value) [-1] ... )(): ... (__import__('operator').setitem( ... spam, ... (1), ... _Qzwk5j5q64__value), ... _Qzwk5j5q64__value) [-1] ... )() 10 #> spam >>> spam {2: 10, 1: 10}
See also:
operator.setitem
,operator.delitem
,zap!
.
- hissp.macros._macro_.setQzLSQB_QzHASH_(lookup, items, value)#
set[###
âsetsubâ Injection. Subscription with assignment.Returns the value assigned (not the collection updated).
#> (define spam (list "0000")) >>> # define ... __import__('builtins').globals().update( ... spam=list( ... ('0000'))) #> set[###-1] spam set[###::2] spam "ab" ; Chained assignment. >>> ( ... lambda _Qzuwg7puku__items, ... _Qzuwg7puku__value=( ... lambda _Qzuwg7puku__items, ... _Qzuwg7puku__value=('ab'): ... [_Qzuwg7puku__value ... for(_Qzuwg7puku__items[::2])in[_Qzuwg7puku__value]][0] ... )( ... spam): ... [_Qzuwg7puku__value ... for(_Qzuwg7puku__items[-1])in[_Qzuwg7puku__value]][0] ... )( ... spam) 'ab' #> spam >>> spam ['a', '0', 'b', 'ab']
items
can be||
if set by another macro likedoto
.#> (doto (dict) set[###1] || 2) >>> # doto ... (lambda _Qzogaeaa42__self=dict(): ... (( ... lambda _Qzuwg7puku__items, ... _Qzuwg7puku__value=(2): ... [_Qzuwg7puku__value ... for(_Qzuwg7puku__items[1])in[_Qzuwg7puku__value]][0] ... )( ... _Qzogaeaa42__self, ... ), ... _Qzogaeaa42__self) [-1] ... )() {1: 2}
- hissp.macros._macro_.spQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
subprocess.
assp#
.
- hissp.macros._macro_.spyQzHASH_(expr, file='sys..stderr')#
spy#
Printexpr
=>
its value, to the file. Return the value.Typically used to debug a Lissp expression.
#> (op#add 5 spy##file=sys..stdout(op#mul 7 3)) >>> __import__('operator').add( ... (5), ... # hissp.._macro_._spy ... # hissp.macros.._macro_.let ... ( ... lambda _Qz764kzbp5__e=__import__('operator').mul( ... (7), ... (3)): ... (__import__('builtins').print( ... __import__('pprint').pformat( ... ('operator..mul', ... (7), ... (3),), ... sort_dicts=(0)), ... ('=>'), ... __import__('builtins').repr( ... _Qz764kzbp5__e), ... file=__import__('sys').stdout), ... _Qz764kzbp5__e) [-1] ... )()) ('operator..mul', 7, 3) => 21 26
- hissp.macros._macro_.tbQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
traceback.
astb#
.
- hissp.macros._macro_.tfQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
tempfile.
astf#
.
- hissp.macros._macro_.thrQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
threading.
asthr#
.
- hissp.macros._macro_.throw(exception)#
Raise an exception.
#> (throw Exception) ;Raise exception objects or classes. >>> # throw ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... Exception) Traceback (most recent call last): ... Exception #> (throw (TypeError 'message)) >>> # throw ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... TypeError( ... 'message')) Traceback (most recent call last): ... TypeError: message
See also:
throw-from
, engarde,The raise statement
.
- hissp.macros._macro_.throwQzH_from(exception, cause)#
throw-from
Raise an exception with a cause, which can be None.If
exception
is not an instance ofBaseException
, it will be presumed an exception class and called with no arguments before attaching the cause to the resulting instance.#> (throw-from Exception (Exception 'message)) ; Explicit chaining. #.. >>> # throwQzH_from ... # hissp.macros.._macro_.throwQzSTAR_ ... (lambda g:g.close()or g.throw)(c for c in'')( ... # hissp.macros.._macro_.let ... ( ... lambda _Qzzkusd5eu__G=(lambda _Qzzkusd5eu__x: ... # hissp.macros.._macro_.ifQzH_else ... (lambda b, c, a: c()if b else a())( ... __import__('builtins').isinstance( ... _Qzzkusd5eu__x, ... __import__('builtins').BaseException), ... (lambda : _Qzzkusd5eu__x), ... (lambda : _Qzzkusd5eu__x())) ... ): ... # hissp.macros.._macro_.attach ... # hissp.macros.._macro_.let ... ( ... lambda _Qzwawunnb6__target=_Qzzkusd5eu__G( ... Exception): ... (__import__('builtins').setattr( ... _Qzwawunnb6__target, ... '__cause__', ... _Qzzkusd5eu__G( ... Exception( ... 'message'))), ... _Qzwawunnb6__target) [-1] ... )() ... )()) Traceback (most recent call last): ... Exception
- hissp.macros._macro_.throwQzSTAR_(*exception)#
throw*
âthrow starâ Creates a closed generator and calls.throw
.Despite PEP 3109,
.throw
still seems to accept multiple arguments. Avoid using this form except when implementing throw method overrides. Preferthrow
instead.The 3-arg form is deprecated as of Python 3.12.
- hissp.macros._macro_.timeQzHASH_(expr, file='sys..stderr')#
time#
Print ms elapsed runningexpr
to the file. Return its value.Typically used when optimizing a Lissp expression.
#> time##file=sys..stdout(time..sleep .05) >>> # hissp.macros.._macro_.let ... (lambda _Qz2dtk7y5j__time=__import__('time').time_ns: ... # hissp.macros.._macro_.letQzH_from ... (lambda _Qz2dtk7y5j__start, _Qz2dtk7y5j__val, _Qz2dtk7y5j__end: ... (__import__('builtins').print( ... ('time# ran'), ... __import__('pprint').pformat( ... ('time..sleep', ... (0.05),), ... sort_dicts=(0)), ... ('in'), ... __import__('operator').truediv( ... __import__('operator').sub( ... _Qz2dtk7y5j__end, ... _Qz2dtk7y5j__start), ... # Decimal('1E+6') ... __import__('pickle').loads(b'cdecimal\nDecimal\n(V1E+6\ntR.')), ... ('ms'), ... file=__import__('sys').stdout), ... _Qz2dtk7y5j__val) [-1] ... )( ... *( ... _Qz2dtk7y5j__time(), ... __import__('time').sleep( ... (0.05)), ... _Qz2dtk7y5j__time())) ... )() time# ran ('time..sleep', 0.05) in ... ms
See also:
timeit
.
- hissp.macros._macro_.twQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
textwrap.
astw#
.
- hissp.macros._macro_.unless(condition, *body)#
Unless the condition is true, evaluates each expression in sequence for side effects, resulting in the value of the last. Otherwise, skips them and returns
()
.#> (any-map c 'abcd #.. (unless (op#eq c 'b) #.. (print c))) >>> # anyQzH_map ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda c: ... # unless ... (lambda b, a: ()if b else a())( ... __import__('operator').eq( ... c, ... 'b'), ... (lambda : ... print( ... c) ... )) ... ), ... 'abcd')) a c d False
See also:
when
.
- hissp.macros._macro_.utQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
unittest.
asut#
.
- hissp.macros._macro_.uuidQzHASH_(hex)#
uuid#
Universally Unique Identifier tag.Abbreviation for
uuid.UUID
, with ademunge
for symbols. Curly braces, hyphens, and a URN prefix are optional, but the argument must be a read-timestr
, not anint
.#> uuid#{urn:uuid:12345678-1234-5678-1234-567812345678} >>> # UUID('12345678-1234-5678-1234-567812345678') ... __import__('pickle').loads(b'ccopy_reg\n_reconstructor\n(cuuid\nUUID\nc__builtin__\nobject\nNtR(dVint\nL24197857161011715162171839636988778104L\nsb.') UUID('12345678-1234-5678-1234-567812345678')
See also:
inst#
.
- hissp.macros._macro_.when(condition, *body)#
When the condition is true, evaluates each expression in sequence for side effects, resulting in the value of the last. Otherwise, skips them and returns
()
.#> (any-map c 'abcd #.. (print c) #.. (when (op#eq c 'b) #.. (print 'found) #.. :break)) >>> # anyQzH_map ... __import__('builtins').any( ... __import__('builtins').map( ... (lambda c: ... (print( ... c), ... # when ... (lambda b, c: c()if b else())( ... __import__('operator').eq( ... c, ... 'b'), ... (lambda : ... (print( ... 'found'), ... ':break') [-1] ... ))) [-1] ... ), ... 'abcd')) a b found True
See also:
if-else
,unless
,The if statement
.
- hissp.macros._macro_.wrnQzHASH_(_Qzx522g6n4__attr, /, *_Qzx522g6n4__args, **_Qzx522g6n4__kwargs)#
Aliases
warnings.
aswrn#
.
- hissp.macros._macro_.zapQzAT_(qualname, f, *args)#
zap@
âzapatâ Augmented attribute assignment operator.The current attribute value becomes the first argument. Returns the value assigned (not the collection updated).
Mnemonic: zap @tribute.
#> (define spam (types..SimpleNamespace : foo 10)) >>> # define ... __import__('builtins').globals().update( ... spam=__import__('types').SimpleNamespace( ... foo=(10))) #> (zap@ spam.foo operator..iadd 1) >>> # zapQzAT_ ... # hissp.macros.._macro_.setQzAT_ ... # hissp.macros.._macro_.let ... ( ... lambda _Qzqfrecvdx__value=__import__('operator').iadd( ... spam.foo, ... (1)): ... (# hissp.macros.._macro_.define ... __import__('builtins').setattr( ... spam, ... 'foo', ... _Qzqfrecvdx__value), ... _Qzqfrecvdx__value) [-1] ... )() 11 #> spam >>> spam namespace(foo=11) #> (zap@ spam getattr 'foo) >>> # zapQzAT_ ... # hissp.macros.._macro_.setQzAT_ ... # hissp.macros.._macro_.let ... ( ... lambda _Qzj2zgvjrn__value=getattr( ... __import__('builtins').globals().__getitem__( ... 'spam'), ... 'foo'): ... (# hissp.macros.._macro_.define ... __import__('builtins').globals().update( ... spam=_Qzj2zgvjrn__value), ... _Qzj2zgvjrn__value) [-1] ... )() 11 #> spam >>> spam 11
See also:
set@
,zap!
,operator.iadd
,Augmented assignment statements
,:@##
.
- hissp.macros._macro_.zapQzBANG_(items, key, f, *args)#
zap!
âzapbangâ Augmented item assignment operator.The current item value becomes the first argument. Returns the value assigned (not the collection updated).
Mnemonic: zap !tem.
#> (define spam (dict : b 10)) >>> # define ... __import__('builtins').globals().update( ... spam=dict( ... b=(10))) #> (zap! spam 'b op#iadd 1) ; Augmented item assignment, like +=. #.. >>> # zapQzBANG_ ... # hissp.macros.._macro_.let ... ( ... lambda _Qzm6fx4xxk__items=spam, ... _Qzm6fx4xxk__key='b': ... # hissp.macros.._macro_.setQzBANG_ ... # hissp.macros.._macro_.let ... ( ... lambda _Qzwk5j5q64__value=__import__('operator').iadd( ... _Qzm6fx4xxk__items.__getitem__( ... _Qzm6fx4xxk__key), ... (1)): ... (__import__('operator').setitem( ... _Qzm6fx4xxk__items, ... _Qzm6fx4xxk__key, ... _Qzwk5j5q64__value), ... _Qzwk5j5q64__value) [-1] ... )() ... )() 11 #> spam >>> spam {'b': 11}
See also:
set!
,zap@
,Augmented assignment statements
.
- hissp.macros._macro_.zapQzLSQB_QzHASH_(lookup, items, callableQzPLUS_args)#
zap[###
âzapsubâ Injection. Augmented subscription assignment.The current item value becomes the first argument. Returns the value assigned (not the collection updated).
#> (define spam (list "abcd")) >>> # define ... __import__('builtins').globals().update( ... spam=list( ... ('abcd'))) #> zap[###:2] spam (op#iadd "XY") >>> (lambda _Qzvibdgdly__items: ... # hissp.macros.._macro_.let ... ( ... lambda _Qzvibdgdly__value=# hissp.macros..QzMaybe_.QzH_QzGT_ ... __import__('operator').iadd( ... (_Qzvibdgdly__items[:2]), ... ('XY')): ... [_Qzvibdgdly__value ... for(_Qzvibdgdly__items[:2])in[_Qzvibdgdly__value]][0] ... )() ... )( ... spam) ['a', 'b', 'X', 'Y'] #> spam >>> spam ['a', 'b', 'X', 'Y', 'c', 'd']
items
can be||
if set by another macro likedoto
.#> (doto |[2]| zap[###0] || (op#iadd 1)) >>> # doto ... (lambda _Qzogaeaa42__self=[2]: ... ((lambda _Qzvibdgdly__items: ... # hissp.macros.._macro_.let ... ( ... lambda _Qzvibdgdly__value=# hissp.macros..QzMaybe_.QzH_QzGT_ ... __import__('operator').iadd( ... (_Qzvibdgdly__items[0]), ... (1)): ... [_Qzvibdgdly__value ... for(_Qzvibdgdly__items[0])in[_Qzvibdgdly__value]][0] ... )() ... )( ... _Qzogaeaa42__self, ... ), ... _Qzogaeaa42__self) [-1] ... )() [3]
Caution
The lookup injection must be written twice: once to read and once to write. In the unusual case that it has a side effect, it will happen twice. Consider
zap!
instead.