<discocaml>
<gooby_diatonic> Oh, I thought there was only Seq.zip so I've been converting all my lists to seq for those purposes :derp:
wingsorc has joined #ocaml
Frostillicus has quit [Read error: Connection reset by peer]
johnridesabike has joined #ocaml
mange has quit [Quit: Zzz...]
wingsorc__ has joined #ocaml
wingsorc__ has quit [Read error: Connection reset by peer]
wingsorc has quit [Read error: Connection reset by peer]
Frostillicus has joined #ocaml
wingsorc__ has joined #ocaml
Haudegen has joined #ocaml
<discocaml>
<contificate> Doesn't combine have that annoying behaviour, different from Haskell, where it won't truncate the list, it'll throw exception in case where lists are unequal length
<discocaml>
<._null._> (It does)
<discocaml>
<contificate> making it, in my mind, not as nice as zip
<discocaml>
<._null._> But also, why do you have lists of different lengths ? Haskell does since they have the list of positive integers, but OCaml doesn't
<discocaml>
<contificate> it's a useful side effect I think
<discocaml>
<contificate> Haskell can zip lazily evaluated infinitely long lists with finite ones
<discocaml>
<deepspacejohn> Seq.zip works like that, fwiw.
<discocaml>
<contificate> slay
<discocaml>
<._null._> seqs are (can be) infinite, so that makes sense (also the naming is consistent)
inline has quit [Remote host closed the connection]
YuGiOhJCJ has quit [Quit: YuGiOhJCJ]
tronexte has quit [Ping timeout: 260 seconds]
tronexte has joined #ocaml
Frostillicus has quit [Ping timeout: 252 seconds]
inline has joined #ocaml
<reynir>
all my zippers are finite
* reynir
ducks
<discocaml>
<yawaramin> if we had `( let+ )` and `( and+ )` then we wouldn't have the naming problem...
<discocaml>
<contificate> bro is zipping the zipping of zippers
<discocaml>
<deepspacejohn> They're very useful for monads and DSLs.
<discocaml>
<contificate> anything in CPS generally
<discocaml>
<deepspacejohn> I tend to use a generic `let ( let@ ) = ( @@ )` a lot. Very handy.
dhil has quit [Ping timeout: 244 seconds]
Anarchos has joined #ocaml
<companion_cube>
for sure
<discocaml>
<barconstruction> I don't understand this
Frostillicus has quit [Quit: Frostillicus]
<discocaml>
<barconstruction> `let@ x = e1 in e2` should be equivalent to `(@@) e1 (fun x -> e2)` which is just `e1 (fun x -> e2)` right?
<discocaml>
<shadowkestrel> i think i see but i also dont see
<discocaml>
<contificate> yeah, so `@@` is applicaton, letting you write CPS in what appears to be direct style
<discocaml>
<barconstruction> Ah, okay, that makes sense
<discocaml>
<contificate> as monadic style is a generalisation of CPS, using a monadic bind as the definition of the operator is also common - but I think anything sequentialised through continuations benefits from these operators
<discocaml>
<shadowkestrel> ohhh that's what you meant by CPS
<discocaml>
<shadowkestrel> i am too tail_mod_cons pilled to think about continuation passing /lh
<discocaml>
<deepspacejohn> `let@` works with anything that takes a continuation. So you can use it for functions like `let@ chan = In_channel.with_open_bin stdin` or generically for any "bind" rather than define a bindop for each one `let@ a = Result.bind b in let@ x = Option.bind y`
<discocaml>
<deepspacejohn> the former is what I tend to use it for the most.
<discocaml>
<barconstruction> Are there any implementations of functional languages that actually optimize away tail calls in general (not necessarily recursive) so that a series of function calls in CPS style use constant stack space? Does scheme do this?
<discocaml>
<deepspacejohn> doesn't OCaml do that?
<discocaml>
<deepspacejohn> I guess I don't actually know.
<discocaml>
<deepspacejohn> it does optimize tail calls in general but I don't know the details.
<discocaml>
<barconstruction> If it's not recursive then the caller and callee have different shapes for their stack frames, different numbers of arguments, different numbers of local variables and so on. So it's a bit more complicated to overwrite it in place
inline has quit [Remote host closed the connection]
inline has joined #ocaml
<discocaml>
<shadowkestrel> I feel like OCaml does tail-call optimise everywhere, while looking through docs I've seen references to using CPS to avoid stack overflows from "the old times" when native-code programs used a conventional callstack instead of the GC-provided one we have now
Anarchos has quit [Ping timeout: 260 seconds]
<discocaml>
<Kali> pretty sure the ocaml compiler guarantees tailcalls everywhere
<discocaml>
<Kali> if you're ever in doubt, you can always use the [@tailcall] attribute to check
<discocaml>
<Kali> pretty sure the ocaml compiler guarantees tailcalls everywhere it's possible to have one
<discocaml>
<shadowkestrel> oh yeah i think where i saw it mentioned was in discussion of `format6` and its associated functions, which uses a lot of TCO
<discocaml>
<Kali> (f [@tailcall]) x
<discocaml>
<shadowkestrel> oh yeah i think where i saw it mentioned was in discussion of `format6` and its associated functions, which uses a lot of CPS
<discocaml>
<Kali> lua is a rare example of an imperative language that does tailcalls everywhere it can too
Anarchos has joined #ocaml
<discocaml>
<Kali> it's actually where i first learned about the concept
<discocaml>
<shadowkestrel> the ES6 spec includes tail call optimisation
<discocaml>
<shadowkestrel> the big 3 implementors (v8, spidermonkey, javascriptcore) do not care, so it doesnt really matter
<discocaml>
<shadowkestrel> the ES6 spec includes tail call optimisation
<discocaml>
<shadowkestrel> the big 3 implementors (v8, spidermonkey, javascriptcore) do not, so it doesnt really matter
<discocaml>
<barconstruction> Can someone explain how this works without going into overwhelming detail? So let's say `g` takes three parameters and requires say 4 local variables in the sense of four words in its stack frame. And `f` needs no parameters and needs two local stack variables for its computations, before concluding with a tail call to g. What does the process look like for calling g in a way that allows the computer to reclaim f's stack space?
Serpent7776 has joined #ocaml
<discocaml>
<zarakshr> `g`s stack frame will just overwrite `f`s, you just need a `jmp g`
Haudegen has quit [Quit: Bin weg.]
Anarchos has quit [Quit: Vision[]: i've been blurred!]
<discocaml>
<Kali> ^ there's nothing left to execute in f, f's result is exactly g's result and so you can just jump straight to g
<discocaml>
<shadowkestrel> i was hoping a few minutes in godbolt.org would be instructive but now i am just more confused about how ocamlopt works
inline has quit [Quit: Leaving]
Anarchos has joined #ocaml
reynir has quit [Ping timeout: 252 seconds]
Humean has quit [Read error: Connection reset by peer]
Humean has joined #ocaml
inline has joined #ocaml
Anarchos has quit [Ping timeout: 268 seconds]
Tuplanolla has joined #ocaml
Anarchos has joined #ocaml
nirvdrum7418 has quit [Ping timeout: 268 seconds]
Anarchos has quit [Quit: Vision[]: i've been blurred!]
nirvdrum741 has joined #ocaml
<discocaml>
<froyo> > if we had ( let+ ) and ( and+ ) then we wouldn't have the naming problem...
<discocaml>
<froyo> right, it'd become a hard-to-lookup syntax/operator problem instead :P
bartholin has quit [Remote host closed the connection]
humasect has joined #ocaml
inline_ has joined #ocaml
inline has quit [Ping timeout: 260 seconds]
humasect has quit [Quit: Leaving...]
zor has joined #ocaml
itszor has quit [Ping timeout: 244 seconds]
<discocaml>
<contificate> 😏 If you faithfully compile CPS (a-la Appel's "Compiling with Continuations"), you can avoid the stack entirely - so "the stack" becomes linked continuation closures on the heap
<discocaml>
<contificate> most people think the problem of making anything tail recursive is hard: it's the constant space part that takes effort
<discocaml>
<contificate> making something tail recursive amounts to CPS conversion - where all calls are in tail position
<discocaml>
<contificate> I don't think there's a generic algorithm for this, as you often have to exploit little tricks - but perhaps I'm wrong
<discocaml>
<contificate> to be clear: for using constant stack space, not CPS conversion
<discocaml>
<contificate> GC provided?
<discocaml>
<contificate> I think you just mean the fiber/cactus stack that OCaml 5 uses now, which is heap allocated
<discocaml>
<contificate> my understanding is you explicitly `discontinue` delimited conts in OCaml 5 to avoid leaks, so "GC provided" may not be accurate