beneroth changed the topic of #picolisp to: PicoLisp language | The scalpel of software development | Channel Log: https://libera.irclog.whitequark.org/picolisp | Check www.picolisp.com for more information
f8l has quit [Ping timeout: 246 seconds]
beneroth has quit [Ping timeout: 246 seconds]
fbytez has quit [Remote host closed the connection]
abu[7] has quit [Ping timeout: 272 seconds]
fbytez has joined #picolisp
theruran has quit [Ping timeout: 272 seconds]
payphone has quit [Write error: Connection reset by peer]
casaca has quit [Read error: Connection reset by peer]
theruran has joined #picolisp
theruran has quit [*.net *.split]
switchy has quit [*.net *.split]
ello has quit [*.net *.split]
DKordic has quit [*.net *.split]
Nistur has quit [*.net *.split]
ello has joined #picolisp
DKordic has joined #picolisp
Nistur has joined #picolisp
theruran has joined #picolisp
switchy has joined #picolisp
casaca has joined #picolisp
payphone has joined #picolisp
switchy has quit [Read error: Connection reset by peer]
switchy has joined #picolisp
theruran has quit [Quit: Connection closed for inactivity]
abu[7] has joined #picolisp
abu[7] has left #picolisp [#picolisp]
abu[7] has joined #picolisp
<geri> hi-hi
<geri> my script's in a usable state now
<geri> happy
<geri> runs like 2 times faster than sbcl version because sbcl doesn't optimize for startup speed XD
<abu[7]> Cool! :)
<geri> any idea how could i call a function that returns a predicate?
<geri> like it returns another function that is a predicate :D
<abu[7]> Good question. I have no convention in that direction.
<geri> okay i wrote a wrapper instead
<geri> i made next/previous song functions very slow
<geri> but now they actually notify me data about song upon calls
<geri> so probably worth it
<geri> is it weird to have a global variable start with @?
<geri> like @REQUEST-ID
<geri> because i need to fill it somewhat often xd
<abu[7]> I think it is right, as it is a Pattern-Wildcard symbol
<geri> oh btw, you said i can use (get) to get values from alists
<geri> it doesnt work for some reason
<abu[7]> It is only fos symbolic keys (pointer equality)
<abu[7]> s/fos/for
<abu[7]> Same as 'asoq'
<geri> '((key1 123) (key2 456))
<geri> shouldnt this work?
<abu[7]> Yes, returns (123)
<abu[7]> (cdr (asoq 'key1 '((key1 123) (key2 456))))
<geri> hm
<abu[7]> (get '((key1 123) (key2 456)) 'key1)
<geri> weird, now it works
<geri> maybe i messed something up with the arguments
<abu[7]> 👍
<geri> *and* it can get values from nested alists
<geri> very nice
<geri> i finally found out why (use) is a thing
<geri> basically if you have defined a variable X on top level
<geri> you can setq it from a function and itll affect top level
<geri> so if you (use) you can make sure it doesnt mess with outer variable
<geri> (im using the setq fact in my script)
<abu[7]> Right, or other assignments like 'match' or 'native'
<abu[7]> Also repeated assignments in 'loop's
<geri> found it out when realized why i couldnt set global variables within functions in my lisp :D
<geri> also found out its how it works in scheme like that
<geri> (de) also introduces a new binding on current level no matter what, right?
<abu[7]> Yep
<abu[7]> Sets the value of a symbol
<geri> check out this horrifying creature
<geri> :D
<abu[7]> I still wonder why realpath works
<abu[7]> In any case you should (use R ..
<geri> im using R there, isnt it how you had it
<geri> R is a symbol though
<abu[7]> Yes, being set by native
<abu[7]> so I would expect you put it in the end
<abu[7]> OK, it works because you return 'S
<abu[7]> But as I said I think it is dangerous
<abu[7]> 'native' allocates anp discards the struct
<abu[7]> so it is deallocated
<geri> it descards the struct, not the outputs, no?
<geri> struct is a C string
<geri> outputs are pico "strings", ie bunch of cells
<geri> so they're different things, no?
<abu[7]> it is parsed from the struct
<geri> yes
<geri> parsed, and now we have a separate object, no?
<geri> if i delete the struct it doesnt matter because string is already parsed
<abu[7]> I'm not sure if this memory is safe
<geri> and saved in a symbol
<abu[7]> If you use the return value, you don't need R
<geri> i wish i knew what R actually is
<geri> XD
<abu[7]> But I'm not sure if this is safe
<geri> oh no
<geri> without R it crashes
<geri> if used in a lop
<geri> loop
<abu[7]> Better use R and put a string into it
<geri> char *realpath(const char *restrict path, char *restrict resolved_path)
<abu[7]> not a list of characters
<geri> thats probably why it clashes xd
<abu[7]> That's what I meant yesterday
<geri> is resolved_path is NULL, string gets malloc'd instead
<geri> hm
<abu[7]> T
<abu[7]> tricky
<geri> im pretty happy with my script all things considered
<abu[7]> native allocates the struct from the nrgument list, fills R, and discards the mem
<abu[7]> Yes, but perhaps this acceses free'd memory
<abu[7]> Let me check the sources of native
<geri> if it accessed freed memory i bet it'd crast 10k times while testing q
<abu[7]> No, depends
<abu[7]> it is allocated on the stack
<abu[7]> From the ref: "native takes care of allocating memory for strings, arrays or structures, and frees that memory when done"
<geri> so all is good?
<abu[7]> No
<abu[7]> The return value is the pointer to the struct
<geri> (%@ "getenv" 'S "TERM")
<geri> from the manual for %@
<geri> how is this any different from realpath example
<abu[7]> Good point
<geri> afaik the base idea is - %@ allocates some buffer, no idea how much and fills it with data that realpath returns
<geri> after, it allocates a symbol (cause 'S) normally and returns that as the response
<geri> and then the buffer gets discarded
<abu[7]> Thats the question
<abu[7]> *when* it is discarded
<geri> output value is now on the heap as usual symbols are with 0 references to original buffer
<geri> idk, you wrote it, you tell me :D
<geri> but in my experience this realpath is pretty reliable so far
<geri> when i read wrong memory it usually crashes my programs every 5th or so time
<abu[7]> I dig into it, forgot the details
<geri> anyway, script works and works nicer than ever before
<geri> happi
<geri> i love not having to covert between strings and symbol and numbers
<abu[7]> Such memory behavior is not predictable. May work a million times for a give calling setup
<abu[7]> and is still by luck
<geri> eh
<abu[7]> because the setup does not yet overwrite the mem
<abu[7]> let me dig into it
<abu[7]> The question is *when* it is freed
<geri> while you're researching ill go for a walk
<geri> laters
<abu[7]> 👍
<abu[7]> 'native' does (tailcall (ffi Exe Lib Fun Args))
<abu[7]> 'ffi' calls 'ffiCall' in src/lib.c
<abu[7]> 'ffiCall' allocates the structs on the stack, fills variables like 'R', and returns
<abu[7]> Thus the memory of the struct is no longer valid
<abu[7]> 'ffi' thea looks at the return value
<abu[7]> In case of "realpath" this is however the pointer to the struct (which may still be on the stack on a lower address, but can any time be overwritten)
<abu[7]> So there are 2 "correct" ways:
<abu[7]> (use R (%@ "realpath" 'N "lib.l" '(R (`PATH_MAX C . `PATH_MAX))) (pack R))
<abu[7]> or
<abu[7]> (buf P PATH_MAX (%@ "realpath" 'S "lib.l" P) (struct P 'S))
<abu[7]> (%@ "getenv" 'S "TERM") is OK, because getenv() returns a pointer to a static string in the environment
<abu[7]> I would do this:
<abu[7]> (buf P PATH_MAX (struct (%@ "realpath" 'P "lib.l" P) 'S))
<abu[7]> btw, the 'S five lines above was wrong, should be NIL
<abu[7]> But (buf P PATH_MAX (struct (%@ "realpath" 'P "lib.l" P) 'S)) is the shortest and fastest, avoids first consing and then packing a list
ello has quit [Quit: ZNC 1.9.1 - https://znc.in]
ello has joined #picolisp
<geri> abu[7]: but char string[] = "hello"; & transient symbol "hello" are completely different things, no?
<geri> iirc all cells are supposed to be heap allocated, no?
<geri> i get the buf solution but i guess i dont get the original one cause lists with R as first element are not documented in native
<abu[7]> Yes, C strings and symbols are different
<abu[7]> The allocation of the symbol from the pointer returned from realpath happens *after* 'ffiCall' returned
<abu[7]> and the stack buffer was allocated *in*'ffiCall'
<geri> hm
<geri> is it some limitation of native?
<geri> doesnt sound like expected behaviour to me
<abu[7]> It completely correct
<abu[7]> realpath returns the arg pointer
<abu[7]> If you want to use it, you must be in control of it
<abu[7]> With (buf P PATH_MAX ... *you* control 'P'
<abu[7]> If you pass a list, native controls it
<abu[7]> creates is, extracts a value, and frees it
<abu[7]> It does not know about realpath
<abu[7]> That's how C behaves. You can allocate buffer on the stack local in a function, and then return a pointer to it to the caller. Boom!
<abu[7]> geri: "lists with R as first element are not documented in native" - They are
<abu[7]> Ref native: "structures, passed as lists with .."
<abu[7]> "a variable in the CAR (to receive the returned structure data"
<geri> uh
<geri> okay, but i didnt even know that - R was from your example
<geri> XD
<abu[7]> I did not explain :)
<abu[7]> In any case, I would go with the last version
<abu[7]> In Vip it is different, it needs a list of chars instead of a single symbol
<geri> how does having a dot in evaluated expression work?
<geri> or even better maybe - how do i loop over a dotted list
<abu[7]> You mean a pait of two atoms?
<geri> ('(@ (rest)) 'a . 'b) # => (a 5932720620683)
<geri> i dont get this basically
<geri> a pair of two things yes
<abu[7]> '@' evaluates all CARs
<abu[7]> The number is 'quote'
<abu[7]> ('(@ (rest)) (quote . a) quote . b)
<abu[7]> So @ sees 2 args
<abu[7]> 'b' is ignored
<geri> that looks very scuffed not gonna lie
<abu[7]> (de f @ .. is not a FEXPR
<geri> but it doesnt eval one of it's last arguments
<abu[7]> It evaluates both args
<abu[7]> (quote . a) quote
<geri> (apply '(@ (rest)) (quote 1 2 . 3)) # => 1 2
<geri> hmmmmm
<abu[7]> All list operations stop on an atomic CDR
<abu[7]> map etc
<geri> makes sense
<abu[7]> It is also for speed, the interpreter stops at an atom: (while (pair ...
<abu[7]> Usually the atom is NIL
<abu[7]> it is ignored ;)
<abu[7]> (mapc println (1 2 3 . 4))
<geri> very weird
<geri> but makes sense too
<abu[7]> Yeah, what else to do
<geri> mapcar literally has "car" in its name
<abu[7]> Doing lots of analyzes of the final Cdr would just waste time
<geri> 4 is cdr, so logically it shouldnt be used
<abu[7]> Yes, a tradeoff
<abu[7]> For other funs like map it is not so clear from the name
<abu[7]> More relevant is this for functions like 'append' or 'conc'
<abu[7]> (append (1 2 . 3) (4 5 . 6)) -> (1 2 4 5 . 6)
<geri> oof
<geri> common lisp only allows dots in quoted cons cells
<geri> '(a . b)
<geri> kinda realizing why now xd
<geri> its not such a big problem though
<abu[7]> Can't be compiled well perhaps
<geri> or because of these weird semantics
<abu[7]> T
<abu[7]> Clojure does not even have cons pairs at all :(
<geri> isnt clojure just cons on cons on cons?
<geri> xd
<geri> or you mean literal pairs
<abu[7]> No, it has only lists as Java arrays internally (for performance I suppose), and an array cannot have such an atomic end
<abu[7]> I had similar thoughts when writing ErsatzLisp
<abu[7]> so I implemented lists not as arrays but made each cell an object iirc
<abu[7]> software-lab.de/ersatz.tgz
<geri> oh
<geri> yeah probably for performance
<geri> i wrote something: https://0x0.st/XyYh.l
<abu[7]> A replacement for 'fill'?
<geri> kinda yeah
<abu[7]> nice
<geri> one benefit over fill - you can do arbitrary expressions inline
<abu[7]> Not in 'fill'?
<geri> not as far as I know
<geri> sec
<abu[7]> ie. ^
<geri> okay wait
<geri> now ill find out i was just stupid?
<geri> xd
<abu[7]> Perhaps similar
<abu[7]> Not sure, I don't know backquote well
<geri> okay i just didnt know i guess
<geri> XD
<abu[7]> np :)
<geri> at least i wrote something
<geri> i dont have splice unquote yet either so
<abu[7]> Speaking of CL, I did 'setf': http://pb1n.de/?fb78ed
<abu[7]> setf is a perverse concept
<abu[7]> semantically
<abu[7]> I did it just as a joke
<geri> its like C assignment
<geri> you can just say string[7] = 'c'
<abu[7]> Right
<geri> setf is super complicated though
<geri> what's going on with that let?
<geri> it seems like reassigning some builtins
<abu[7]> Destructuring bind
<abu[7]> yes
<geri> well, first one i know, but the rest is kinda weird
<abu[7]> As you say
<abu[7]> redefining
<geri> so (setf (car A) 'x) is same as (set (prog??? A) 'x)
<geri> why prog xd
<geri> do you use it as identity or something
<abu[7]> We need to stop one mem access earlier
<abu[7]> prog is the "no-op" function
<abu[7]> returns the evaluated arg
<geri> identity == '((X) X)
<abu[7]> T
<abu[7]> just faster
<geri> okay
<abu[7]> 'prop' is one step "earlier" than 'get'
<geri> okay
<abu[7]> (setf (get 'A 'x) 7) is (set (prop 'A 'x) 7)
<geri> so this setf is all syntactic sugar
<abu[7]> Right
<abu[7]> very useless
<geri> :D
<abu[7]> just compjications
<geri> if c is symbol, then `(a b ',c) => (a b 'symbol)
<geri> how do i do this with fill?
<abu[7]> ^(list c)
<abu[7]> It "splices" iirc
<geri> it does
<geri> i mean, i want the quote in final list
<geri> for magical reasons
<geri> :D
<abu[7]> ^(list (lit c))
<geri> huh
<geri> okay i guess that works
<abu[7]> I have not tried
<abu[7]> ok
<geri> (let C 'Symbol (fill '(A B ^(list (lit C))))) => (A B 'Symbol)
<geri> so seems fine
<abu[7]> (setq c 'S) (fill (1 ^(list (lit c)) 9))
<abu[7]> T
<geri> well, my poor little backquote is useless
<geri> very sad
<abu[7]> :(
<geri> i still managed to write it though, very proud
<abu[7]> yes, good thing
<geri> except it cant do splicing
<geri> maybe ill write that part for fun
beneroth has joined #picolisp
<geri> here
<geri> i have no idea why it works!
<geri> :D
<geri> hi bene
<abu[7]> (cond ((atom) a) ((pair) b)) is a bit overkill ;) (if (atom) a b) should do
<abu[7]> In any case very nice
<geri> ikr :D
<beneroth> Ahoy geri, abu[7] :)
<abu[7]> o/
<geri> hihi
diogenes has joined #picolisp
<diogenes> hello, i was curious what the equivalent for let* was in picolisp. I want to define things locally sequentially and be able to refer to them in my function.
<abu[7]> Hi diogenes! PicoLisp's 'let' behaves like 'let*'
<abu[7]> (ie. binding one after the other)
<diogenes> oh then my function must have another bug with it...
<diogenes> (de time-in-secs (n unit)
<diogenes> (let
<diogenes> (seconds 1
<diogenes> minutes (* 60 seconds)
<diogenes> hours (* minutes minutes)
<diogenes> days (* hours 24)
<diogenes> work-days (* 8 hours)
<diogenes> weeks (* days 7)
<diogenes> work-weeks (* days 5)
<diogenes> months (* days 31)
<diogenes> years (* days 365)
<diogenes> work-months (* work-weeks 4)
<diogenes> work-years (* work-weeks 49) )
<diogenes> (case unit
<abu[7]> The let looks fine
<diogenes> hmm
<diogenes> then my case is fucked up
<abu[7]> Please note that for locally bound symbols upper case is recomended
<diogenes> okay
<abu[7]> (let (Seconds ...
<abu[7]> But here is no conflict I think
<abu[7]> What goer wrong?
<diogenes> well it doesn't return anything when i run (time-in-seconds 2 sec) -> NIL
<diogenes> I expect 2
<abu[7]> Perhaps some typo in one of the variables?
<abu[7]> '*' gives NIL if any of the args is NIL
<abu[7]> I would set a breakpoint
<abu[7]> (! case unit
<diogenes> okay thank you
<abu[7]> Then look at each symbol
<diogenes> let me try that now
<abu[7]> 👍
<diogenes> okay weird it says that seconds is NIL
<diogenes> so there must be something weird happening with the let binding
<abu[7]> 'minutes' is also NIL then?
<diogenes> yes so is weeks etc
<abu[7]> Strange indeed
<diogenes> it says time-in-seconds -- Undefined
<abu[7]> Just from looking it seems ok
<abu[7]> But you called it?
<abu[7]> to get to the breakpoint
<diogenes> yes
<abu[7]> It is time-in-secs
<diogenes> lol no wonder
<diogenes> it works now lol
<diogenes> type
<diogenes> typo
<abu[7]> good
<diogenes> i learned about break points so that is a success imo
<abu[7]> hours (* minutes minutes) is correct, but more clear would be 60
<diogenes> :pray:
<abu[7]> ')
<abu[7]> :)
<diogenes> how would i go about adding something like a documentation string to my functions? kind of like cl's defun that includes and optional doc string. does plisp have a way to do this?
<abu[7]> Not really, just com
<abu[7]> ments
<diogenes> okay
<beneroth> no built-in for that, but it would be possible in principle
<beneroth> e.g. making another variant of (de) which then sets a documentation string as property, similar to how (de) sets the *Dbg and doc properties
<beneroth> then again, why do a doc-string when you have the full source :)
<diogenes> hmm
<diogenes> i guess i do like to just do (explain 'func)
<diogenes> no need to nav to file
<diogenes> kind of like being able to pp
<beneroth> there is (pp) for that :)
<diogenes> but pp ignores comments
<beneroth> T
<diogenes> also some functions are foriegn. and pp de gets you just apointer
<diogenes> so functions like that
<diogenes> pp doesn't help
<beneroth> when you started picolisp in debug mode (with + argument at the end in CLI), you can do (de my-func ...) and then (show 'my-func) to see the 'doc and '*Dbg property of the 'my-func symbol which were put by (de)
<beneroth> built-ins refer here to their source code in the LLVM code
<diogenes> yeah i see that now
<diogenes> hmm
<beneroth> on one hand, programmers should strife to name and structure the code clear-enough for it to be self-explanatory. on the other hand, this is not always possible. on third-hand, in cases where the code does such a complex thing a short string is probably not a good enough explanation and it needs a dedicated txt file anyway.
<diogenes> I see what you mean, sometimes when deving i usually just put a doc-string as like a way to remind what this function should do i guess. but what you said i understand
<beneroth> well, find a way which works for you and makes you productive :)
<diogenes> T
<beneroth> I use comments a lot, especially to explain functions or their parameters. and I try to have a certain system/pattern when naming things.
<diogenes> what does your system look like?
<beneroth> a lot is also just a matter of habit. Picolisp favours shorter names as it has no strong separation between source code and the running program, the running program is just a binary representation in memory.
<beneroth> so shorter code uses less memory and therefore is often also faster
<beneroth> afk for a while
<beneroth> back already
<beneroth> diogenes, it's really highly recommended to follow the naming convention, protects you from most accidental mistakes: https://software-lab.de/doc/ref.html#conv
diogenes has quit [Ping timeout: 246 seconds]
f[x] has joined #picolisp
f[x] has quit [Remote host closed the connection]