- inserting pretty-printed forms of arbitrary data into a string of some
structure is useful
- eg logging conventions
- eg human readable callbacks
- how a data type gets pretty-printed should be abstracted away from the string
- ie no
%x
idiom
- ie no
- allow users the ability to trivially customize
- recursively walk through mixed lists (ie type
0h
) - allow projection semantics with argument-dependent arity
name | description |
---|---|
.fmt.S | separator that defines insertion points. defaults to ^ . can be any char or string |
.fmt.H | defines the head char of a mixed list. defaults to ( . can be any char or string |
.fmt.T | defines the tail char of a mixed list. defaults to ) . can be any char or string |
.fmt.D | defines the delimiter between entries of a mixed list. defaults to ; . can be any char or string |
.fmt.MT | dictionary that maps types to their string representations. defaults are omitted here. inspect the code and alter to preference |
name | description |
---|---|
.fmt.sexp | produces a formatted string given an s-expression |
.fmt.mexp | produces a formatted string given an m-expression |
q)/ .fmt.sexp takes a (<string>;<any>;<any>;...) q).fmt.sexp("^ went to the ^ to buy ^ ^, but only ^ were available";"rj";`market;10;"pies";5.5) "rj went to the market to buy 10 pies, but only 5.5 were available" q)/ too few entries per separator ignore the trailing separators q).fmt.sexp("^ went to the ^ to buy ^";`rj;"store") "rj went to the store to buy ^" q)/ and too few separators per entry ignore the trailing entries q).fmt.sexp("^ went to the";`rj;"store") "rj went to the"
q)/ .fmt.mexp takes a [<string>;<any>;<any>;...] q).fmt.mexp["^ went to the ^ to buy ^ ^, but only ^ were available";"rj";`store;11;"pizzas";6.6] "rj went to the store to buy 11 pizzas, but only 6.6 were available" q)/ if too few entries per separator, .fmt.mexp partially formats the string q)/ up to the given entries, returning a function with an arity of the number q)/ of missing entries q)f:.fmt.mexp["^ went to the ^ to buy ^ ^, but only ^ were available";"rj";`store] q)f k){m:&/#:'(y;z);$[m;f1[x;m#y;wt'm#z];x]}["rj went to the store to buy ^ ^, but only ^ were available";28 30 42]enlist[;;] q)/ note the partially formatted string and its arity q)f[11;"pizzas";6.6] "rj went to the store to buy 11 pizzas, but only 6.6 were available" q)/ if you need these precomputation semantics out of order, just combine q)/ .fmt.sexp and .fmt.mexp q)logger:.fmt.mexp["^ ",.fmt.sexp[("^ [^] ";"RDB";"DB")],"^"] q)logger k){m:&/#:'(y;z);$[m;f1[x;m#y;wt'm#z];x]}["^ RDB [DB] ^";0 11]enlist[;] q)/ the static middle part is precomputed q)logger[.z.t;"the db just died bro"] "05:15:27.769 RDB [DB] the db just died bro" q)/ .fmt.mexp is not bounded above by typical arity limits q)f:.fmt.mexp[" "sv 10 1#"^"];f[`by;"order";`of;"the";10;`peaky;`blinders;"-";`thomas;`shelby] "by order of the 10 peaky blinders - thomas shelby"
q)/ inserting "" operates idiomatically q).fmt.sexp("a^b^c";"";"") "abc" q)/ mixed lists are recursively resolved q).fmt.sexp("^ is a mixed list";(`a`b;1 2.;("apple";([]1 2 3)))) "(a b;1 2;(apple;[x:1 2 3])) is a mixed list" q)/ enums are resolved to their backing data q)x:`a`b`c;a:`x!0 2 0 0 1 q).fmt.sexp("where did the enum go, ^?";a) "where did the enum go, a c a a b?"
q)/ you can change .fmt.S, .fmt.H, .fmt.T, and .fmt.D to arbitrary q)/ characters or strings q).fmt.S:"%^&";.fmt.H:"<";.fmt.T:">";.fmt.D:" | " q).fmt.sexp("%^& would %^& look at a nested %^&";`why;"anyone";(1 2;3 4.;(2021.05.23;`weirdness))) "why would anyone look at a nested <1 2 | 3 4 | <may 23 2021 | weirdness>>" q)/ it's trivial to customize the type specializer, as q)/ .fmt.MT[<short>]:<lambda>[<any>] -> <string> q)/ if you don't like the defaults, change them q).fmt.MT[10h]:upper;.fmt.MT[-7h]:{string[x],"j"} q).fmt.sexp("he screamed, %^&, as he ate %^& pies on %^&";"GOT is overrated";19;2021.01.01) "he screamed, GOT IS OVERRATED, as he ate 19j pies on jan 1 2021"