[00:02:54] anyone know of a good prerolled haskell concatenative play around I could use [00:03:39] hackerfoo: That was written in response to my article in which I used "row" due to a misunderstanding :P [00:04:07] And later edited it [00:04:13] i got the type of [3] wrong above by the way, it's "3" has that type. [3] puts a function on the stack just like [+] [00:04:40] Well, it sounds nice, at least :) [00:07:03] Oh right, row types are generalized records, indexed by a label. [00:08:20] Maybe I'll just call it 'context'. [00:17:24] I found this but it shows a bunch of fails https://groups.google.com/forum/#!topic/catlanguage/HNIM7loIdQk [00:19:29] mh better go back to my Kitten program or I'll never finish it [00:27:45] evincar: there's this thing I call the "overhang problem" when using colon in the python way [00:27:50] where you have code like this [00:27:55] if(some long condition that [00:28:15] needs more than one line): [00:28:25] code that's supposed to be within the if [00:29:06] basically the second line is really a continuation of the first since the ( ) continue it [00:29:12] so it should be valid to write like that [00:36:42] Yeah, the layout rule could definitely be improved [00:37:21] I wanted to keep it simple, so right now, after a colon it looks for a token whose source column is greater than the indentation of the line with the colon [00:37:41] Then any number of tokens (or bracketed series of tokens) indented at least as much as that first token [00:38:07] It seems to work well in practice but suffers from some limitations, including that [00:43:13] I think you just need to set the column to be greater than to be the one that starts the beginning of the continued line [00:44:28] e.g. in the above the column is at 'if' [00:45:03] not even sure what python does [00:46:20] yeah it works in Python [00:46:23] The problem is that it's done by token, before parsing [00:47:16] So it has no knowledge that "if (...)" is the beginning of a term and should be treated as a unit [00:47:38] you don't need to know everything [00:47:45] I can either special-case those things, or do the desugaring during parsing, but both seem less than ideal [00:47:56] the only relevant thing is the ( ) matching [00:48:10] it only needs very basic parsing [00:48:28] literally match up [] {} () and ignore every other token [00:49:02] also I think you're doing something wrong when you have multiple : on the same line [00:49:33] the line continuation should be for the rightmost one and the others also scope out at the same time [00:49:41] I handle whitespace while parsing by attaching the char * of both the token and the line in which it occurs to the token. [00:50:42] Basically: struct token { char *token, char *line, size_t length, token_type type } [00:52:04] Then detecting a line is just line != previous_line, and the indentation is t.token - t.line. [00:52:31] I found this don't know if this is any good http://kpreid.livejournal.com/7351.html re: concenative in haskell [00:52:57] he manages to write fibonacci recursively in it thougb so it doesn't look bad [00:56:10] * jtimon [jtimon!~quassel@117.29.134.37.dynamic.jazztel.es] has quit (Ping timeout: 260 seconds). [01:01:44] These formulations are usually missing some polymorphism, but yeah, it works okay [01:02:05] Kitten also has that problem at the moment--had a fix that didn't work [01:02:32] Basically you can't apply a quotation multiple times on different stacks [01:02:50] I know how to solve it now but it would involve a fairly large change to the typechecker :/ [01:06:02] is that similar to the problem I was talking about earlier with "f dip f apply" ? [01:06:25] where f is something with variable arity [01:19:20] * jtimon [jtimon!~quassel@117.29.134.37.dynamic.jazztel.es] has joined the channel. [01:20:45] funnily enough I'm trying to define that right now in Kitten [01:22:11] and it doesn't work [01:22:28] define call2 [01:22:28] (Xs..., T, T, (Xs..., T -> Ys..., Xs... +P) -> Ys..., Ys..., Xs...) -> f: [01:22:31] f dip f call [01:23:50] this is the sort of stuff I want Starpial to be able to handle [01:24:15] I don't think it's even representable as nested pairs [01:25:11] oh yeah and obviously I missed a +P [01:26:30] so Ys... can't be variable arity because I need to write it twice [01:26:54] so Ys has to be just Y [01:27:18] Xs... is in the wrong place so it simply can't be there at all [01:28:19] so then I get define call2 (T, T, (T -> Y +P) -> Y, Y +P) -> f: [01:28:43] which is obviously fine but not very interesting or useful except for basic things [01:30:02] Yeah, they're related problems [01:30:17] You can't even tell if this is recursive: dup 1 swap apply [01:30:36] "-> f; f dip f call" == "-> f; -> x; f call x f call" [01:31:10] So you're calling f on both S... and S..., T [01:31:47] Also you can't have multiple stack variables in a row like that, like "Ys..., Xs..." [01:32:46] You can only be polymorphic in the "rest" of the stack [01:33:25] Or rather, "Ys..." represents the whole stack state below [01:33:47] It's not just "some elements of the stack" [01:34:22] I know [01:34:50] anyway I forgot you defined this in the prelude already as to_both albeit with a messy implementation with loads of local variables [01:35:22] Yep [01:35:28] Those locals are necessary for now, sadly [01:35:32] why [01:35:37] I wrote it without [01:35:44] I used one variable for f [01:35:54] f dip f call [01:36:09] Hm [01:36:22] I thought I still had a bug where you can't call the same function on different stack states [01:36:28] I know it breaks in some circumstances [01:36:36] Maybe my hackish fix works in that case :P [01:37:03] yeah I forgot to test it, it doesn't work [01:37:17] Namely, I treat the type of to_both, " (A, A, (A -> B) -> B, B)" [01:37:42] as though it were " (R..., A, A, (S..., A -> S..., B) -> R..., B, B)" [01:37:59] yeah I know, that's the same [01:38:00] With a rank-2 type [01:38:26] But I do this *after* inference when it should propagate through *during* inference [01:39:11] And I know how to fix this using bidirectional typechecking instead of the current (mostly) vanilla HM [01:39:21] It's just a bunch of work :/ [01:39:45] It would, however, improve type error messages a lot [01:39:49] So I need to do it at some point [01:39:56] yeah, sounds fun [01:40:11] Type errors are currently bad mostly because I provide way too much context [01:40:15] And don't pretty-print types [01:40:24] So you see all the gross T10245 shit [01:41:01] It does at least tend to pinpoint the source location where types mismatched [01:41:04] I know I mentioned this already but I think it would be good if you could write stuff like {+ [01:41:13] {+} and {2 +} {+ 2} [01:41:36] I suppose? You can do \+ \(2 +) \(+ 2) [01:41:38] yeah I've found it finds that right place in the source, except it shows it at the top [01:42:45] the \+ is obviously better but the other two use an extra char :P [01:44:10] also you might be a situation where you want to write : + 2 [01:44:54] do (splitwhen): = c [01:45:21] Yeah, was just thinking that combines pretty well with "do" [01:45:23] the error for that is horrible [01:45:33] There are already so many syntaxes for those things :/ [01:45:41] It's already going to be a style problem [01:46:06] I've been trying to use the style I use in my own programming language as much as possible [01:46:16] so using the colon notation a lot [01:46:48] That's fair [01:47:06] do (splitwhen): \(= c) doesn't look nice [01:47:12] \(= c) splitwhen [01:47:12] is ok [01:47:30] That would actually be do (splitwhen): (= c) [01:47:52] Assuming you want it to desugar to {(= c)} splitwhen [01:48:02] oops yeah [01:48:15] Like, the parens are kind of annoying but at least explicit [01:48:41] but yeah, they're just not necessary when the binary function is already missing an argument [01:48:44] "if (length = 2)" would be prettier than "if (length (= 2))" [01:49:24] sure in Kitten I'm using the full infix when possilbe [01:49:47] in Starpial I have to write infix like length _=_(2) [01:49:53] I started an updated tutorial by the way [01:49:55] https://www.gitbook.com/book/evincarofautumn/programming-with-kitten/details [01:50:04] Using the new compiler [01:50:12] good [01:50:14] Deleted the old compiler yesterday because it was just causing confusion [01:50:24] And I can get to anything I need from it in the git history anyway [01:50:36] Which isn't much at this point [01:50:53] So that's -12kloc :) [01:51:22] Part of that size is just me figuring out how to build all this shit [01:51:29] It could be done in far less code, I think [01:51:38] My eventual goal is to get it down to like 4kloc [01:51:49] Something digestible by the average person familiar with compilers [01:52:19] The problem is that 80% of the code handles 20% of the features, all the edge cases and defaults that make the language nice(r) to use [01:52:24] idk I'd maybe say work on the new features first then try to simplify the code later [01:52:34] Yeah, doing that as much as I can anyway [01:52:43] Some things need to be simplified to make progress right now [01:52:49] yeah fair enough [01:53:05] The dictionary is a mess and it's making it hard to implement things like generic instances of traits [01:53:19] Which are obviously a blocker for release [01:54:33] I feel like 'curry' word should maybe be intrinsic? [01:54:37] Cat called it papply [01:55:09] -> x f: {x f call} [01:55:24] but I think if intrinsic it could be more efficient [01:55:53] Maybe, it shouldn't be bad even if not intrinsic [01:56:14] I recently redid closure conversion to simplify things, a couple things left to figure out before that lands [01:57:25] I say it could be more efficient because you can literally prepend an object to the existing code of the quotation f [01:57:29] But that would compile to "{ -> closure.0, closure.1; closure.0 closure.1 call } new.closure.2" [01:57:39] I.e. just push a function pointer and cast the stack [01:57:48] Actually [01:57:59] Just "{ call } new.closure.2" eta-reduced [01:59:12] (Assuming unboxed closures, which are the next step after finishing this closure-conversion thing.) [02:00:46] is there any reason you need the comma for stuff like -> x, f: [02:00:57] I keep forgetting it and this is supposed to be a stack language [02:01:18] each token is a variable anyway [02:01:44] the comma could be optional but requiring it is a bit meh [02:02:10] https://github.com/evincarofautumn/kitten/issues/160 [02:02:34] Basically commas help with error messages and recovering during parsing [02:02:51] And they're consistent with the rest of the language that uses commas for the same reasons [02:03:39] Kitten isn't meant to be minimalistic [02:04:19] There are many concessions to make it more usable, practical, and familiar to people coming from the C family [02:04:51] ok I suppose that's a fair justification [02:04:55] Forthers tend to show up and complain about it, and their criticisms are certainly valid [02:04:58] But Kitten is not a Forth [02:05:36] neither is Starpial of course [02:05:46] in Starpial commas mean assert one value has been placed on the stack since the last comma [02:05:59] which turns out to be very useful for understanding the code [02:06:13] and for code inside () they're actually required [02:06:27] you have to put ( ;) if you want to say there's nothing there [02:06:35] or ( ;;) for there's anything in there [02:06:54] and I have a special operator for .., which does .. plus removing the assertion for you for that part [02:07:15] took a while to come up with a consistent set of syntax [02:07:51] you're allowed to have empty () as well just for the special case of doing f() [02:08:02] and (1,) is also valid [02:08:53] define curry [02:08:54] (T, (Xs..., T -> Ys... +P) -> (Xs... -> Ys... +P)) -> x, f: {x f call} [02:09:28] add it to your common.ktn lol [02:10:12] this is one of the interesting cases where the permissions get copied from one quotation to another [02:10:40] I'll accept PRs ;) [02:10:56] Gonna add a few of the words you've mentioned anyway [02:11:14] And yeah, permissions are nice sometimes [02:11:19] I hope to make them more useful/usable over time [02:12:01] You'll notice that the function type of "curry" doesn't mention a permission variable, so it gets a new default one, like +Q [02:12:10] Meaning the closures have the same permissions, but curry is pure [02:12:19] Yay for good defaults [02:12:48] if I made a pull request it would probably rewrite all your words to match up with the naming I use my Starpial prelude :P [02:12:56] so I'm not sure you'd want that [02:13:03] Please do not, haha [02:13:11] To be fair, I don't have naming 100% figured out [02:13:27] I'm pretty happy without about 70% of my prelude vocab [02:13:42] I was working on it today to get the Forth like words better sorted out [02:13:52] I'm trying to come up with more descriptive names like both/to_both/both_to instead of bi/bi*/bi@ [02:14:01] yeah I don't like those from factor [02:14:06] Because I can never remember which is which [02:14:21] I only use bi for bi [02:14:33] to_both is apply2 [02:15:02] both_to would be "spread" or something? [02:15:25] can't even remember if I have that one [02:15:49] ah [02:15:54] sorry your both_to is my bi [02:16:01] I have both for your both [02:16:15] my bi is factor's bi [02:16:45] so both/to_both/both_to = both/apply2/bi [02:17:01] like I said I'm pretty happy with my naming [02:17:19] I didn't like 'cleave' from factor so I called it 'multi' [02:17:28] to go with 'bi' and 'tri' [02:18:04] I might make a PR anyway this week and you can take what you want [02:18:28] I like the idea of a common vocabulary between languages [02:19:18] I might rename apply apply2 apply3 applyn to call call2 call3 calln [02:19:37] because of the discussion earlier about how functions are applied and quotations are called [02:19:57] but then you call functions too [02:20:10] eh they are synonyms pretty much :( [02:21:11] Yeah, I just chose "call" because it's shorter [02:21:19] I was about to mention that [02:21:24] It was "apply" for a while [02:21:37] in Starpial you'd never actually write apply because it's just # [02:21:40] it's a built in operator [02:21:42] In super early versions of Kitten it was postfix "@" [02:22:16] any reason why you wouldn't go back to that? [02:22:33] or is it because all your operators are infix? [02:22:58] btw @ looks more like apply than call [02:23:11] Mostly the infix operators thing [02:23:17] And yeah, it was a mnemonic for @pply [02:23:40] to think of it I don't really like the use of 'call' because it sounds too low level and scary [02:23:53] I could add prefix/postfix operators but I would need to change operator sections to (_ + 1) instead of just (+ 1) [02:24:06] no please don't :) [02:24:25] And have a way of disambiguating them so you could have unary "-" and binary "-" [02:24:38] Currently it's "neg", which isn't ideal, but at least it's consistent [02:24:41] you could do what hackerfoo did and call it 'ap' [02:24:55] in Starpial I use -~ for unary negation [02:24:56] Yeah, true [02:25:09] similar to OCaml which uses ~- sometimes [02:25:49] I'm thinking to have a special case syntax for -alpha that turns it into a unary operator [02:25:54] but it only works in front of words [02:26:06] I think that covers a lot of cases where you need it though [02:26:13] e.g. -sqrt(n) [02:26:20] -my_var [02:27:16] I'm gonna vote for 'ap' rather than 'call' or 'apply' [02:28:07] With unboxed closures, "call" can actually be compiled as the x86 "call" instruction, which is nice [02:28:16] I like the low-level feel [02:28:35] I know what you mean but it's just a bit dirty feeling for me [02:28:45] Fair enough [02:28:56] ap is quite gritty, apply is the airy fairy word [02:29:25] ap bi dip tri both keep multi [02:29:37] ^ all my functional combinators [02:30:06] id drop nip tuck dup over pick swap rot roll [02:30:12] ^ shuffle words [02:30:22] quote curry compose [02:30:55] _?#_ if_t if_f if elif else endif [02:31:19] I don't have any syntax for if in Starpial [02:32:01] empty head tail chop top init pop push append prepend in contains indexof unique [02:32:04] ^ list words [02:32:24] I have syntax for indexing .[n] (same as >[n]) and <[n] [02:32:40] loop while until untilfail whilefail dowhile dountil fix times [02:32:43] ^ loopy words [02:32:56] ah and then there's the list functionals.... [02:33:42] map each filter filterout takewhile takeuntil leavewhile leaveuntil splitwhen fold foldr reduce reducer scan scanr spread spreadr find findr findmatch findmatchr locate removeat remove forall exists dowhilefound dountilfound [02:34:11] unify applied applicable failneg proveifthen proveiff [02:34:21] ^ logical words (using my Prolog like functionality) [02:34:50] solo duo trio list count countdown to tob dto dtoa iota [02:35:17] yeah I've got loads more as well [02:35:33] they maybe need reorganised a bit [02:36:04] I have weird non-deterministic ones like @choose?[TODO]: #{_.. x _..} x [02:36:26] yeah I need to finish writing the types lol [02:38:21] @merge?[TODO]: {#{}}`{#{ps.. {x xs..} qs..} x, merge{ps.., if_f(xs empty): xs, qs..}..}# [02:38:36] takes a bunch of lists and interleaves them non-deterministically [02:39:17] hoping to be able to combine that with parallelism so you can sink multiple live input sources [02:47:07] I think how it would work is when there are side effects the system is allowed to choose any non-determinism path it likes (kinda at random but not really) [02:47:31] and after there are side effects it loses the ability to process the other non-deterministic paths so if it fails it fails [02:50:19] Makes sense, once an effect happens you've "observed" a path and can't backtrack [02:50:25] Unless you have something like STM transactions [02:50:47] it would be nice to have some ability to backtrack [02:50:57] even if it's not *always* possible [02:51:46] also in starpial all code is inherently transactional and you have to break code down using . and .> for sequencing points [02:52:26] so if you have "a# . b#" it's allowed to perform the side effects in b first [02:54:23] so if you have producers a b c then you could do "a# . b# . c# . merge do_stuff#" [02:54:40] * jtimon [jtimon!~quassel@117.29.134.37.dynamic.jazztel.es] has quit (Ping timeout: 268 seconds). [02:55:30] merge{a# . b# . c#} . do_stuff I meant [02:56:00] do_stuff has data dependencies on the merged list but you can still do stuff before the lists have finished being created [03:10:31] evincar: you should maybe call 'concat' just 'cat' ehehe [03:10:40] I have it called 'cat' in my prelude [03:11:04] ["Meow", "!"] cat say [03:22:57] evincar: your nested comments don't seem to work as described in the docs [03:23:38] main.ktn:229.38-38:unexpected "/*"; expected [03:26:05] Hm, strange, thought that was tested [03:26:51] I can't believe you're still using it after all the issues you've discovered [03:27:03] I mean, I do appreciate it [03:27:57] trying to finish this damned program lol [03:28:20] evincar: synonyms don't seem to work neither? [03:28:41] I wrote synonym pq_push priorityqueue::push [03:28:43] They do not :/ [03:28:59] Another problem with how the dictionary works right now [03:38:15] Eventually imports will be implemented using synonyms [03:54:40] just had a weird idea [03:54:53] calling stack effects with words that represent the stack effect [03:55:16] e.g. ba for swap [03:55:27] bca for rot [03:55:37] aa for dup [03:55:49] aba for over [03:56:13] abca for 3 pick [03:56:17] I think I've seen that in some esoteric language [03:56:36] it's pretty easy to use and understand though [03:56:58] True [03:56:58] doesn't work for drops but works for a bunch of stuff [03:56:59] You can't represent drops [03:57:21] actually you can represent some drops [03:57:21] Yeah, and I guess you have to infer the number of arguments from the names used [03:57:40] b [03:57:47] = swap swap drop [03:57:49] that would be A B -> B [03:57:55] a.k.a. NIP [03:58:05] Oh I see what you mean [03:58:13] I was reading it in the other direction [03:58:22] B A -> B [03:58:58] An effect comment would cover everything for a "pure" concatenative combinator language [03:59:15] swap = [A] [B] -- [B] [A] [03:59:25] drop = [A] -- [03:59:37] call = [A] -- A [04:00:10] I've been wanting to write a pure term-rewriting language for a while, have a few basic implementations [04:00:23] At each step, find the most specific matching pattern and replace it with its substitution [04:00:48] The notion of "most specific" gets kinda hairy for more expressive patterns though [04:01:01] hmm [04:03:28] evincar: when are you planning to add that fat arrow => assignment thing? [04:03:45] that would make writing this code sooooo much easier [04:04:01] you hardly need to muck about with stacks at that point [04:04:09] Could also use indices, like {; }: swap = {2; [0] [1]}, drop = {1;}, call = {1; 0}, id = {0;} [04:04:29] I dunno, probably after I get codegen working again [04:05:44] Mutation for values should be straightforward because it's still "pure" [04:06:06] Mutation of variables or mutable references is more fraught, and will allow reference cycles unfortunately :/ [04:06:50] https://github.com/evincarofautumn/kitten/issues/146 [04:07:01] Has some thoughts on local-only mutable refs [04:07:16] hackerfoo: I just realised you can modify variables using dip4 or something if you don't rely on other stuff in the stack [04:08:14] evincar: yeah that's what I was referencing [04:08:37] You can do it even if you rely on other things in the stack: [+] pushl dip11 [04:09:33] oh right yeah, currying [04:09:47] swap = {2; [0] [1]} is like a condensed version of my bytecode: [04:09:50] * hackerfoo sent a long message: hackerfoo_2017-06-13_04:08:47.txt [04:13:26] evincar: record access would be pretty useful as well using .field notation [04:14:27] I guess I can write an accessor function for now [04:20:48] in fact if you've got a useful set of variables lumped together you can just [04:20:51] do (dip2): [04:23:41] kernelj: We were talking about alts earlier [04:24:04] You can see how many a function consumes in the top line of the bytecode printout [04:24:11] Like: ___ algorithm.sum_ (1 -> 1) x2 rec ___ [04:24:42] xN means it consumes N-1 per call, so sum_ would consume 1 alt per call. [04:25:22] and you can't get them back? [04:25:26] x1 is omitted for functions that don't consume any alts. [04:26:10] Not in a single evaluation. This limitation only applies to the interpreter, though. [04:27:30] So "[1 2 3 ... 32] sum" fails in the interpreter, but works when compiled. [04:29:19] The only way to fix this will be to prove that the different paths are exclusive. I might be able to do some hack that will cover most cases, but in general, I will probably need something like a SMT solver. [04:30:50] I could maybe add an annotation that a function only returns once, similar to Prolog's cut. [04:31:35] But it only comes up when playing with the interpreter, rather than compiling. [04:32:33] This is because the compiler does the equivalent of a cut after each function, which isn't ideal either. [04:34:19] doesn't that kill off your alts? [04:47:18] Yeah. It assumes that they are exclusive. [04:47:51] The plan is to only allow compilation if they are proven exclusive, otherwise they are inlined. [04:48:07] It's the only efficient way to support alts. [04:49:29] And main is IO -> IO, and IO only supports a single return, so eventually all but one alt must be eliminated. [04:51:47] It's like searching through a maze. One person goes in, and one comes out, having followed a single path. It's just kind of fuzzy in the middle, in that you can try multiple paths, possibly simultaneously, to find out which one works. [04:52:04] But in the end, there is only one that succeeds. [04:53:21] That is why they can't be combined; it's a pure search, not a traversal. [05:00:50] sounds a bit like what I want to do with my alts combined with side effects [05:01:09] once you've done a side effect you can't go back and try a different path [05:01:44] define times (Xs..., Int32, (Xs... -> Xs... +P) -> Xs...) -> n, f: [05:01:47] if (n > 0): f call (n - 1) f times [05:02:00] uff I missed the other +P again [05:02:46] * evincar [evincar!~jonathanp@173-228-12-107.dsl.dynamic.fusionbroadband.com] has quit (Ping timeout: 255 seconds). [05:03:24] The problem with that is that it's now dependent on the order in which alts are evaluated. [05:04:00] The only way to avoid it is to prove only one can succeed, then the order doesn't matter. [05:06:00] for mine I'd just want the runtime to choose a path whichever appears to make the most progress [05:06:19] It may seem inefficient to repeatedly evaluate the conditions for each branch, but at least Clang removes all this. [05:06:31] wow I think I'm nearly done this program, I just need to define dip2 and dip3 [05:07:32] I think you'll find that approach generates worse code, because of all of the data dependencies. [05:08:23] I'm essentially feeding the C compiler very simple graphs, and it knows what to do with them. [05:22:53] my program compiles! [05:24:26] I thought of a trick to recover alts: I could just check the graph when all alts are exhausted, recovering any where all remaining nodes have taken the same path. [05:25:25] aaaand... it doesn't work [05:25:58] It should be pretty fast. It would just be taking a bitwise-or of all alt_sets. [05:31:17] found a bug [05:31:29] from back when I didn't understand Kitten [05:31:47] 0 2 (n_items - index _leftchild) min max [05:31:53] I didn't have the parentheses [05:33:24] evincar: any way you could make these operators safer? [05:33:58] like that's effectively doing without parentheses [05:34:06] 0 - 2 (n_items - index _leftchild) min max [05:34:17] 0 - 2 n_items index _leftchild min max [05:34:55] if it's possible there should be some sort of restriction/checks to stop you putting it in a stupid place [05:36:19] * evincar [evincar!~jonathanp@173-228-12-107.dsl.dynamic.fusionbroadband.com] has joined the channel. [05:36:46] evincar: "kitten: divide by zero" didn't leave a stack trace [05:37:54] I can't even see anywhere there could possibly be a divide by zero =/ [05:38:17] The old compiler had a restriction that the operands of infix operators had to produce exactly one element [05:38:20] I can reinstate that [05:38:51] Hm, stack traces shouldn't be hard to add either [05:41:02] I wonder if it's parsing / 100 % 100 wrong [05:41:07] that would be pretty disastrous [05:42:36] I have no idea where it's getting any divide by zero from [05:44:33] Hm, it shouldn't, / and % are both declared as left-associative with the same precedence [05:45:15] yeah I tested on a little expression and it didn't divide by zero [05:45:56] I'm resorting to good old printf tactics of debugging [05:51:37] the divide by zero is happening on the line with the / 100 % 100 [05:59:18] evincar: ok bug confirmed [05:59:25] "(99999999 / 100 % 100) show say" gives divide by zero error [06:00:48] (0 / 100 % 100) say [06:02:23] (120 / 40 % 30) say gives 12 [06:02:42] * FreeFull [FreeFull!~freefull@defocus/sausage-lover] has quit. [06:03:15] Wow [06:03:46] * evincar [evincar!~jonathanp@173-228-12-107.dsl.dynamic.fusionbroadband.com] has quit (Quit: leaving). [06:04:15] I'm a bit confused why it only gives the divide by zero error if you actually use the result [06:04:37] * evincar [evincar!~jon@173-228-12-107.dsl.dynamic.fusionbroadband.com] has joined the channel. [06:07:24] Probably because something's too lazy in the interpreter [06:08:26] I'm not using the interpreter obv [06:09:22] or maybe I am, depends what happens when you kitten a .ktn file [06:12:24] That's the interpreter still [06:12:33] Yup, the function isn't applied strictly [06:12:42] Pro tip: don't write an interpreter for a strict language in a lazy language :/ [06:14:59] haha [06:15:32] anyway I think my program's about as done as it's gonna get [06:15:41] I'm amazed you got this far [06:18:26] evincar: http://dpaste.com/0WQ9YSQ [06:20:10] this is the same code in Starpial http://dpaste.com/1GBV46F [06:22:23] but yeah, that was hard work compared to doing it in C++ and OCaml [06:23:45] This is neat :) [06:24:19] To be fair, you are the first user outside my immediate circle [06:25:26] So you got to encounter all the bugs [06:26:55] eh, I like a challenge [06:29:24] Optionals would definitely be nicer with monadic operations & sugar [06:32:23] well as you see I wrote bind, so it's mainly the sugar that's missing [06:32:31] Maybe I'll borrow something like monad comprehensions from Haskell [06:33:09] Also needs generic instances (ugh) & higher-kinded types (pretty easy) [06:34:12] I'm guessing the performance of this is also abysmal [06:41:10] You ran into 24 issues, by my count :P [06:41:58] wow, that's a lot [06:44:38] Yup, but once I actually fix them, you'll have saved someone else the frustration [06:46:25] * xkapastel [xkapastel!uid17782@gateway/web/irccloud.com/x-vbjfgxthipaovpcg] has quit (Quit: Connection closed for inactivity). [06:54:02] right I should get some sleep probably, bye for nonw [06:59:51] G'night [07:06:54] * evincar [evincar!~jon@173-228-12-107.dsl.dynamic.fusionbroadband.com] has quit (Quit: leaving). [09:26:05] * jtimon [jtimon!~quassel@117.29.134.37.dynamic.jazztel.es] has joined the channel. [13:32:53] * jtimon [jtimon!~quassel@117.29.134.37.dynamic.jazztel.es] has quit (Ping timeout: 240 seconds). [15:44:25] * FreeFull [FreeFull!~freefull@defocus/sausage-lover] has joined the channel. [17:26:27] * jtimon [jtimon!~quassel@117.29.134.37.dynamic.jazztel.es] has joined the channel. [21:20:22] * kernelj [kernelj!~kernelj@unaffiliated/colonelj] has quit (Ping timeout: 268 seconds). [22:37:40] * flogbot [flogbot!~flogbot@2001:4800:7814:0:2804:b05a:ff04:4ba7] has quit (Ping timeout: 240 seconds). [22:37:47] * flogbot [flogbot!~flogbot@2001:4800:7814:0:2804:b05a:ff04:4ba7] has joined the channel. [22:37:48] :leguin.freenode.net 353 flogbot = #concatenative :flogbot jtimon FreeFull jeaye tgunr Sgeo_ lonjil groovy2shoes mollerse dustinm` MDude rotty rgrinberg flout carvite earl_ shachaf erg koisoke merry rjungemann ephe_meral doublec diginet m_hackerfoo hackerfoo strmpnk kanzure jeremyheiler bmp PiDelport shmibs otoburb puckipedia [22:37:48] :leguin.freenode.net 366 flogbot #concatenative :End of /NAMES list. [22:48:19] * kernelj [kernelj!~kernelj@unaffiliated/colonelj] has joined the channel.