[00:47:08] * xkapastel [xkapastel!uid17782@gateway/web/irccloud.com/x-odwsbipaopziteaf] has joined the channel. [01:48:37] * jamtho [jamtho!~jamtho@host86-138-206-22.range86-138.btcentralplus.com] has joined the channel. [02:23:39] * roachmd [roachmd!~roachmd@2601:cc:4101:d832:8eb:b86f:e838:f771] has joined the channel. [02:27:33] * jamtho [jamtho!~jamtho@host86-138-206-22.range86-138.btcentralplus.com] has quit (Ping timeout: 240 seconds). [02:28:40] * roachmd [roachmd!~roachmd@2601:cc:4101:d832:8eb:b86f:e838:f771] has quit (Ping timeout: 276 seconds). [04:56:25] * roachmd [roachmd!~roachmd@2601:cc:4101:d832:8eb:b86f:e838:f771] has joined the channel. [07:16:52] * xkapastel [xkapastel!uid17782@gateway/web/irccloud.com/x-odwsbipaopziteaf] has quit (Quit: Connection closed for inactivity). [08:12:06] * roachmd [roachmd!~roachmd@2601:cc:4101:d832:8eb:b86f:e838:f771] has quit (Ping timeout: 240 seconds). [08:17:58] * roachmd [roachmd!~roachmd@c-73-43-49-183.hsd1.ga.comcast.net] has joined the channel. [08:24:38] * roachmd [roachmd!~roachmd@c-73-43-49-183.hsd1.ga.comcast.net] has quit (Remote host closed the connection). [08:38:08] * jamtho [jamtho!~jamtho@host86-138-206-22.range86-138.btcentralplus.com] has joined the channel. [08:56:35] * proteusguy [proteusguy!~proteus-g@2405:9800:b408:bc31:9967:5a44:f656:b270] has quit (Ping timeout: 246 seconds). [10:50:06] * jamtho [jamtho!~jamtho@host86-138-206-22.range86-138.btcentralplus.com] has quit (Ping timeout: 248 seconds). [11:16:52] * FreeFull [FreeFull!~freefull@defocus/sausage-lover] has quit. [11:37:40] * evincar [evincar!~jon@75-142-42-181.dhcp.reno.nv.charter.com] has joined the channel. [11:38:14] I'm trying to figure out how to give types to certain special operations in Kitten [11:38:29] "return" jumps to the end of the current definition [11:38:34] "loop" jumps to the start [11:38:43] "jump" tail-calls a closure [11:39:56] My first impression is that they should be polymorphic in their result, because they don't return, basically invoking a continuation [11:41:51] But that's not quite right, because their types need some restrictions [11:45:36] E.g. "return" is basically the identity function, but cancelling everything composed after it [11:46:58] In "define f (-> Int32) { 123 return 3.14 }", "return" should have the type "Int32 -> Int32", and "3.14" is dead code [11:50:18] I guess I could account for these words specially when typechecking compositions, and probably "if" & "match" [11:50:45] "return" is a left zero for composition: "return X" = "return" [11:51:38] And it's the identity function [11:51:41] "loop" is like a call to the current definition, but also a left zero: "loop X" = "loop" [11:52:18] "jump" is like a normal call to a closure, but also a zero [11:54:31] They shouldn't cancel through branches of an "if" or "match", though, unless all branches are cancelling [11:54:58] So "if (a) { b return } else { c return } d" cancels out "d" [11:56:16] But "if (a) { b return } else { c } d" and "if (a) { b return } c d" do not [11:59:53] That seems pretty straightforward [12:00:02] "A1 A2 ... AN B" cancels B if any A is a zero [12:00:19] "if { A1 } elif (...) { A2 } ... else { AN } B" cancels B if all A are zeros [12:18:14] evincar: Why add these operations? They are problematic because none of them are functional. [12:18:45] `loop` is the same as a tail call, right? [12:25:16] In my compiler, I use the bottom type for anything returned from a tail call, and any operation with an input of type bottom is eliminated. This allows a tail recursive function to be specialized/inlined into another function. [12:26:56] I guess your `loop` is like my modified tail call, but a normal tail call would stack up any remaining operations. [12:52:01] hackerfoo: They're not terribly problematic, I was just using the channel to rubberduck [12:53:19] "loop" is a tail call to the current definition, yeah [12:54:57] And indicating that a term is a zero can be done exactly as you say, by eliminating terms that take bottom as input [12:56:11] The main reason to add them is convenience and avoiding nesting [12:57:24] I don't think early return is especially anti-functional [12:58:07] Basically these operators are just specialised continuations for common use cases [13:00:29] Continuations aren't (pure/total) functional because they don't yield a value for an input. [13:01:25] Which is why a monad is required in Haskell to implement continuations. [13:03:11] You can program in CPS in Haskell without using Cont :P [13:08:09] Sure, but you could also compile an imperative language to pure functions in Haskell. [13:08:11] And these are pure, just not total [13:09:23] One of the attractive things to me about concatenative languages is that they have both functional and imperative ways of reasoning about them [13:10:54] And I like being able to explicitly say "tail-call this closure or complain if you can't" [13:12:00] Fair enough. [13:13:43] I think the main difficulty with reasoning about Haskell is due to laziness. [13:14:34] For performance, in particular [13:14:59] Laziness is nice for equational reasoning [13:15:23] This also makes reasoning about Popr more difficult at first, even though there is no performance penalty. [13:16:13] It has to be read backwards, then forwards again. [13:19:15] Just to get an idea of how things will be forced, or what? [13:23:10] Yeah, especially when using assertions: `1 _(_ 2 False ! _)_ drop` -> `1` [13:23:38] The commented brackets are to show what will be dropped. [13:26:00] So it can be tricky to create a dependency to make sure a failed assertion will cause a branch to fail. [13:26:33] You considered prefix syntax before, right? [13:27:30] Something like `0 >= ! drop 0` won't work as expected to limit a value to a positive integer. [13:27:41] Yes, it didn't work out. [13:29:11] With functions that return a single value, it's very Haskell-like, which is good, and supports a similar indentation style. [13:29:43] But it quickly falls apart when using functions that return multiple values. [13:29:45] Ah, yeah, multiple results could get strange to read [13:31:16] So what would be the correct version of that code? [13:31:33] Also, long composition chains with `.` always seem awkward to read in Haskell. [13:32:09] Yeah, never really liked the right-to-left reading order there [13:32:37] >>> from Control.Arrow (also Control.Category I think) is more natural for long chains [13:33:02] Arrow notation in general is a good (verbose, slow) embedding of concatenative code [13:33:24] Which is something I only came to appreciate recently [13:34:56] The overloading of composition is something I haven't really seen done yet in concatenative land [13:35:39] Kitten has something resembling that with permissions, I guess [13:38:02] I've thought about it, but right now I favor using partial evaluation to optimize combinators to achieve the same goals. [13:41:40] I could just write a small interpreter, and then it would get optimized away. [13:45:35] Overloading composition in a concatenative language would be like overloading function application in Haskell. [13:52:33] Typeclass instances for function types get you some of the way there [13:53:38] And "=<<" is basically overloaded application, just not for pure code [13:53:52] Well, non-monadic [13:54:08] You could write everything in Identity if you wanted :P [13:54:38] And it'd make it easier to migrate if you decided you wanted effects later on [14:04:09] * xkapastel [xkapastel!uid17782@gateway/web/irccloud.com/x-qwwtaakjrqpiygis] has joined the channel. [14:04:38] `[0 swap] pushl popr 0 >= ! head` is one way to implement the assertion mentioned earlier. Or `dup 0 >= ! 0 *`. [14:18:00] * roachmd [roachmd!~roachmd@2601:cc:4100:244e:2d39:7249:f8e7:9260] has joined the channel. [14:37:05] * evincar [evincar!~jon@75-142-42-181.dhcp.reno.nv.charter.com] has quit (Ping timeout: 240 seconds). [15:04:40] * roachmd [roachmd!~roachmd@2601:cc:4100:244e:2d39:7249:f8e7:9260] has quit (Remote host closed the connection). [15:54:44] * tgunr [tgunr!~davec@cpe-76-172-43-116.hawaii.res.rr.com] has joined the channel. [16:05:03] * roachmd [roachmd!~roachmd@2601:cc:4100:244e:2d39:7249:f8e7:9260] has joined the channel. [16:09:51] * roachmd [roachmd!~roachmd@2601:cc:4100:244e:2d39:7249:f8e7:9260] has quit (Ping timeout: 246 seconds). [16:17:30] * KeyJoo [KeyJoo!~keyjoo@83.220.188.124] has joined the channel. [16:23:55] * FreeFull [FreeFull!~freefull@defocus/sausage-lover] has joined the channel. [16:48:13] * tgunr [tgunr!~davec@cpe-76-172-43-116.hawaii.res.rr.com] has quit (Read error: Connection reset by peer). [16:50:11] * roachmd [roachmd!~roachmd@2601:cc:4100:244e:2d39:7249:f8e7:9260] has joined the channel. [16:54:31] * roachmd [roachmd!~roachmd@2601:cc:4100:244e:2d39:7249:f8e7:9260] has quit (Remote host closed the connection). [17:28:21] * roachmd [roachmd!~roachmd@2601:cc:4100:244e:2d39:7249:f8e7:9260] has joined the channel. [17:32:05] * tgunr [tgunr!~tgunr@gateway/vpn/privateinternetaccess/tgunr] has joined the channel. [17:33:48] * evincar [evincar!~jon@75-142-42-181.dhcp.reno.nv.charter.com] has joined the channel. [17:51:07] * groovy2shoes [groovy2shoes!~groovy2sh@unaffiliated/groovebot] has quit (Ping timeout: 240 seconds). [18:07:54] * jamtho [jamtho!~jamtho@host86-138-206-22.range86-138.btcentralplus.com] has joined the channel. [18:22:53] * jamtho [jamtho!~jamtho@host86-138-206-22.range86-138.btcentralplus.com] has quit (Ping timeout: 246 seconds). [18:38:18] * groovy2shoes [groovy2shoes!~groovy2sh@unaffiliated/groovebot] has joined the channel. [18:40:59] * Sgeo [Sgeo!~Sgeo@ool-18b98980.dyn.optonline.net] has quit (Ping timeout: 260 seconds). [18:58:48] Woo implementing existentials [18:58:56] Unboxed closures are so close I can taste them [19:20:28] existentials? [19:21:45] found a reference, reading [19:21:47] I'm redoing the implementation of closures, using existential types [19:23:08] An existential is essentially a pair of an abstract type and a value, where the value depends on the type [19:23:41] isnt that kind of like SYMBOL: [19:24:02] the type depends on what is set [19:24:08] A value of type "exists X. t2" is a pair of a type "t1" and a value "v" such that "v" has type "t2[X -> t1]" (t2 with all occurrences of the variable X replaced with t1) [19:24:51] ??? Where did t1 come from? [19:24:59] It's the hidden type [19:25:24] So for example in Kitten say I have a closure that captures a variable of type Int32 [19:25:28] guess i need to see how and why t would be used [19:25:35] E.g. -> x; { x + 1 } [19:25:51] ok understand that [19:26:45] i think i do, as I don't know your kitten syntax [19:27:18] (introduce local x, return quotation that captures x and returns x+1) [19:27:32] That becomes "-> x; x \lambda_lifted_elsewhere pack (Int32) as [X] (Pair Int32)>)" [19:28:10] So I'm hiding the type Int32 in the closure, which stores the Int32 and a pointer to a function that takes it as an argument [19:28:40] "[X] T" means "exists X. T" [19:29:39] And "lambda_lifted_elsewhere" is a top-level definition like "define lambda_lifted_elsewhere (Int32 -> Int32) { -> closure1; closure1 + 1 }" [19:30:17] That's an unboxed closure, which stores the Int32 directly; boxed closures store a pointer to the closure [19:30:37] Unboxed closures require no allocation, but they can't be stored in data structures because they don't have uniform size [19:30:55] ok, why would i want to use this? [19:32:07] To avoid the need to allocate closures on the heap for every use of a combinator such as map/fold/filter [19:33:18] ok, ill believe you :) [19:33:48] It's a fairly low-level performance detail; I expect typical code to use mainly boxed lists & closures because they're more convenient [19:34:46] But for example I started writing a toy kernel in Kitten to see how well it fares in low-level code [19:34:57] I come from the world of assembly, machine code, and hardware, these modern concepts make my head hurt [19:35:26] but i try [19:35:42] So this can guarantee that code doesn't try to allocate on the heap before the memory allocator is set up [19:36:35] (I'm also adding a permission "+Alloc", the permission to allocate, which is granted by default but can be disabled with "-Alloc") [19:36:56] so, its on a stack then? [19:37:15] Yup, -Alloc code can only use the data stack, so that means unboxed arrays and closures [20:04:25] * tgunr [tgunr!~tgunr@gateway/vpn/privateinternetaccess/tgunr] has quit (Ping timeout: 240 seconds). [20:06:27] * roachmd [roachmd!~roachmd@2601:cc:4100:244e:2d39:7249:f8e7:9260] has quit (Ping timeout: 246 seconds). [20:15:35] * Sgeo [Sgeo!~Sgeo@ool-18b98627.dyn.optonline.net] has joined the channel. [20:28:53] * Sgeo_ [Sgeo_!~Sgeo@ool-18b98627.dyn.optonline.net] has joined the channel. [20:29:40] * Sgeo [Sgeo!~Sgeo@ool-18b98627.dyn.optonline.net] has quit (Ping timeout: 258 seconds). [20:36:39] evincar: wanted to say that i was very inspired by your "why concatenative programming matters" post and your work on kitten [20:37:34] I'd like to try and design a concatenative lang myself, like some mix of kitten and purescript [20:43:49] suppi: Thanks, I'm glad you liked it :) [20:44:09] It feels like it needs a follow-up, now that it's been like...5 years [20:44:29] Maybe to coincide with a pre-release of Kitten [20:44:35] "Matters of Concatenative Programming" [20:45:05] If you want to do it, go for it [20:45:11] It's a good learning experience [20:45:47] I wish we had more collaboration on each other's projects in this community, rather than everyone doing their own thing [20:45:55] But at least people's projects seem clearly differentiated [20:47:52] I'd like to see an event-oriented concatenative language, and I've been thinking about making a library for that in Kitten [20:48:03] * Sgeo__ [Sgeo__!~Sgeo@ool-18b98627.dyn.optonline.net] has joined the channel. [20:48:59] Where you have time-varying values and push-based recomputation with event handlers attached [20:49:51] * Sgeo_ [Sgeo_!~Sgeo@ool-18b98627.dyn.optonline.net] has quit (Ping timeout: 246 seconds). [20:51:46] Or something array-oriented, like a more compositional variant of APL or J [20:54:06] Also, Kitten already has a decent amount in common with PureScript; their effect systems are based on the same papers [20:54:19] And I plan to borrow some more things like record types eventually [20:55:58] A JS backend wouldn't hurt [21:05:46] I'm trying to write more about my compiler and language, but I feel like I have to get what I'm writing about working first. [21:06:32] So I start writing, which gets me thinking about the concept more, which leads to finding a bug. [21:07:16] I'm working on an article about partial evaluation. [21:08:10] The nice thing about writing is that it encourages better design, and makes discussions about the design easier. [21:10:28] Popr doesn't have much overlap with any other language I know of, though. [21:13:54] evincar: i'm less interested in JS and more interested in kinds, extensible records and having really good tooling [21:15:08] also, i'd really like a language that can be used for scripting [21:15:29] or being able to write applications that can use the language to control the logic [21:15:35] like emacs-lisp [21:17:17] Kitten is already very close to what I'm thinking about, but I still don't understand concatenative programming very well and for example the advantage of coeffects over monads [21:17:58] so I'm still searching, trying, tweaking, looking for something that ticks for me. maybe at the end i'll discover that what I'm looking for is just kitten :) [21:25:22] also time-varying values is interesting! [21:51:29] * tgunr [tgunr!~tgunr@gateway/vpn/privateinternetaccess/tgunr] has joined the channel. [21:54:30] Could someone explain better how to use hashtables in Factor? I have a sequence of objects of which I would like to extract a slot which has unique value to be used as a keys and I am not seeing how to put the sequence into a hsh table [21:57:03] I do have a method hashcode for the object which determines the key for the object [22:32:50] I just found it I think [22:36:56] map>alist [22:36:56] * flogbot [flogbot!~flogbot@2001:4800:7814:0:2804:b05a:ff04:4ba7] has quit (Ping timeout: 255 seconds).