So... I added some "second stage" parsing functionality, to get the en result in tabular form rahter than as a single [stream_vt], and to check for global errors such as unequal number of columns in the rows, and now I am back to segfaulting! =( However, this time it does not seem to be a stack issue because I run into the segmentation fault already at the compilation stage.
I code in Vim and have it set up so that typing ":make" will run "patsopt -tc -d %", i.e., typechecking only. When I do everything seems fine--no complaints. I have used this utility for some time now and it has always worked like a charm. Wierdly though, if I issue "$ patsopt -tc -d csv_lexer.dats" in the console instead I get a segfault. The same happens for every other compilation command: I've tried compiling just using type checking, just to c, or etc. Always segfault. Compiling with the "-verbose" flag prints exec(patsopt --output csv_lexer_dats.c --dynamic csv_lexer.dats) Segmentation fault exec(patsopt --output csv_lexer_dats.c --dynamic csv_lexer.dats) = 35584 which does not tell me anything. My code can be found at https://github.com/August-Alm/ats_csv_lexer Note that I have moved some function implementations into a hats-file. Might this be a cause of trouble? Any tips at all on how to debug this are most appreciated. I don't know where to even begin as gdb seems useless as long as I can't even generate the C-code. Best wishes, August Den onsdag 8 mars 2017 kl. 23:44:10 UTC+1 skrev gmhwxi: > > >>I take that as being somewhat tongue-in-cheek. ATS is a very theoretical > language, after all. > > I know that this sounds very ironic but interesting stuff often does sound > ironic :) > > My view of programming language research is changing gradually but surely. > I now strongly feel > that the most important programming support is to facilitate the need to > alter/adapt the behaviour > of a written program without actually requiring direct changes to be made > to the program. And the > template system of ATS can be seen as an attempt to provide programming > support of this sort. > > > On Wed, Mar 8, 2017 at 4:47 PM, August Alm <[email protected] > <javascript:>> wrote: > >> See in. >> >> Den onsdag 8 mars 2017 kl. 17:51:36 UTC+1 skrev gmhwxi: >>> >>> Tangential to the topic of monads: Do you know if someone has thought >>>> about the relations between ATS and "enriched effect calculus" (as >>>> described in http://homepages.inf.ed.ac.uk/als/Research/Sources/eec.pdf) >>>> or "linear state monads" (as mentioned in >>>> https://arxiv.org/pdf/1403.1477.pdf)? There is a clear analogy. >>>> Implementing a concept such as a linear state monad in ATS would be nice, >>>> I >>>> think. Monadic programming on an Arduino, anyone? =) It would certainly be >>>> a unique selling point. >>>> >>> >>> I can't really follow these monad papers. Too much for me :) >>> Given your background, maybe you could give this a try? >>> >>> I'm tempted but I feel like I have to understand ATS:s function tags >> ("cloref" and the like, the flavours of function) better first, and >> generally get a more solid footing. I don't want to write something "cool", >> I want it to be useful, too. >> >> >>> Over the years, I have gradually grown more and more cynic about >>> "theoretic" research >>> in the area of programming languages. I feel that the most urgent issue >>> in programming is >>> to find effective approaches to reducing programming complexity. >>> >>> I take that as being somewhat tongue-in-cheek. ATS is a very theoretical >> language, after all. To clarify, I think Haskell suffers greatly from >> having too little focus on efficiency (among many of its users, not among >> the guys working on the compiler). I heard about ATS about the same time as >> I heard about Idris (the dependent type thing) and decided to pursue ATS >> precisely because of its air of efficiency and "real-world-readiness". I do >> still love my Haskell though, mainly because it is so easy to be productive >> with it. Scala has a very good no-bs culture and good library hygiene, but >> I'm not too fond of OOP so... >> >> >>> For instance, in your csv parser, there are a lot of if-then-else's. >>> Maybe you took them from >>> some Haskel code. The point is that if-then-else's make programming hard >>> to write and harder >>> to read/follow. I propose the following style: >>> >>> I first tried to write it using only pattern matching but failed to get >> it passed the typechecker. Maybe I will have another go at it. >> >> >>> 1) Implementing a csv parser without worrying about quotes (DQUOT). Call >>> this version 1. >>> 2) Using templates to improve version 1 without directly modifying >>> version 1. Another way >>> to put it: you still have version 1 available after doing the >>> improvement. >>> >>> If I was uncertain about the algorithm then such an incremental >> development style would surely be preferable, but since the code is a port >> of a tried and tested Haskell library I'm >> not very motivated to scrap and start over. But for my next project(s) I >> will try to heed your words. >> >> I know that this may sound a bit vague but that is my point. Being vague >>> makes people >>> think more and more deeply :) >>> >>> Cheers! >>> >>> >>> On Tuesday, March 7, 2017 at 4:52:58 PM UTC-5, August Alm wrote: >>>> >>>> I'm glad too! I wrote my first "Hello World" program (in Haskell) less >>>> than four months ago, before that I was completely illiterate about >>>> programming--writing a linear, lazy CSV-parser in ATS has definitely been >>>> my most challenging venture so far. I mean this in a good way. ATS is >>>> quickly becoming my favorite language. It is daunting at times, sure, but >>>> its unique combination of low-level abilities and functional abstractions >>>> makes me feel like the Star Trek idiom "To boldly go where no one has gone >>>> before", heh. The ATS sky is so vast I've almost forgot about monads. And >>>> YES!, I do suggest trying ATS to every programmer I meet. >>>> >>>> Tangential to the topic of monads: Do you know if someone has thought >>>> about the relations between ATS and "enriched effect calculus" (as >>>> described in http://homepages.inf.ed.ac.uk/als/Research/Sources/eec.pdf) >>>> or "linear state monads" (as mentioned in >>>> https://arxiv.org/pdf/1403.1477.pdf)? There is a clear analogy. >>>> Implementing a concept such as a linear state monad in ATS would be nice, >>>> I >>>> think. Monadic programming on an Arduino, anyone? =) It would certainly be >>>> a unique selling point. >>>> >>>> I do not understand what you're aiming at with your suggestion to maje >>>> CSVState a datavtype or absvtype. Could you elaborate? I have seen >>>> abstract >>>> types used as a way to make otherwise allowed operation illegal (there is >>>> an example in your book, I think, of how to construct a record type where >>>> some fields are mutable and some are not), but not for the sake of >>>> overloading symbols. >>>> >>>> I will rewrite the code so that DELIM and QNLIN are passed as >>>> templates. I also intend to add some further functionality, like functions >>>> for filtering out errors, for printing and for collecting the output in >>>> tabular form with rows and columns rather than as a single row. When I'm >>>> satisfied I will make an npm-package out of it. >>>> >>>> Best wishes, >>>> August >>>> >>>> Den tisdag 7 mars 2017 kl. 02:21:00 UTC+1 skrev gmhwxi: >>>>> >>>>> Really glad that you got it to work! >>>>> >>>>> I suggest that you make a npm-package for the parser and then >>>>> publish the package. In this way, other ats-lang users can benefit >>>>> from your work easily. >>>>> >>>>> You could try to introduce some abstract types into your code. For >>>>> instance, I would suggest that you make CSVstate a datavtype (linear >>>>> datatype) >>>>> (a datatype is often referred to as being semi-abstract). Then you can >>>>> introduce overloaded symbols for functions processing CSVstate, making >>>>> your code >>>>> more accessible. >>>>> >>>>> Also, the following interface: >>>>> >>>>> extern fun >>>>> lex_csv(QNLIN: bool, DELIM: char, cs: llstring): CSVEntries >>>>> >>>>> can and probably should be changed into >>>>> >>>>> extern >>>>> fun{} >>>>> lex_csv(cs: listing): CSVEntries >>>>> >>>>> The parameters QNLIN and DELIM can be passed via templates: >>>>> >>>>> extern >>>>> fun{} lex_csv$QNLIN(): char >>>>> extern >>>>> fun{} lex_csv$DELIM(): char >>>>> >>>>> implement{} lex_csv$QNLIN() = false >>>>> implement{} lex_csv$DELIM() = ',' // default value >>>>> >>>>> Writing function templates (instead of functions) enables you to move >>>>> your code around very conveniently. You can even move template code >>>>> into the body of another function. >>>>> >>>>> That's all for now. Hope you will like ATS and tell/teach it to your >>>>> friends. >>>>> >>>>> Cheers! >>>>> >>>>> On Monday, March 6, 2017 at 4:06:11 PM UTC-5, August Alm wrote: >>>>>> >>>>>> The code now seems to work as inteded! >>>>>> >>>>>> https://github.com/August-Alm/ats_csv_lexer >>>>>> >>>>>> Thank you for all the help. I still don't fully grokk why the >>>>>> function needs to consume each of its arguments--will have to meditate >>>>>> more >>>>>> on that--but at least I know how to write code like this from now on. >>>>>> >>>>>> Den måndag 6 mars 2017 kl. 17:43:36 UTC+1 skrev gmhwxi: >>>>>>> >>>>>>> Yes, CSVstate needs to be changed as well. >>>>>>> >>>>>>> However, your code needs very little change. This is like a >>>>>>> a 5 minute job to me. I would be happy to give it a try if you say >>>>>>> so. >>>>>>> But I thought that you might want to get the thrill of fixing the >>>>>>> code :) >>>>>>> >>>>>>> On Monday, March 6, 2017 at 11:30:27 AM UTC-5, August Alm wrote: >>>>>>>> >>>>>>>> Hrrm, I had: >>>>>>>> >>>>>>>> fun >>>>>>>> parse_entry >>>>>>>> ( st: !CSVState >> _ >>>>>>>> , at: (int, int) >>>>>>>> , acc: !$SBF.stringbuf >>>>>>>> , cs: llstring >>>>>>>> ) : stream_vt(CSVEntry) >>>>>>>> >>>>>>>> I gather I have to change not just [!$SBF.stringbuf] but also >>>>>>>> [!CSVState >> _], right? What about if I did >>>>>>>> >>>>>>>> fun >>>>>>>> parse_entry_con >>>>>>>> ( st: !CSVState >> _ >>>>>>>> , at: (int, int) >>>>>>>> , acc: !$SBF.stringbuf >>>>>>>> , cs: llstring >>>>>>>> ) : stream_vt_con(CSVEntry) >>>>>>>> >>>>>>>> and then put >>>>>>>> >>>>>>>> parse_entry(...) = >>>>>>>> $ldelay >>>>>>>> ( parse_entry_con(...) >>>>>>>> , ( free(st) >>>>>>>> ; free(acc) >>>>>>>> ; free(cs) >>>>>>>> ) >>>>>>>> ) >>>>>>>> >>>>>>>> --would that work? Would it be idiomatic and efficient? >>>>>>>> >>>>>>>> Thanks, again, >>>>>>>> August >>>>>>>> >>>>>>>> Den måndag 6 mars 2017 kl. 14:30:05 UTC+1 skrev gmhwxi: >>>>>>>>> >>>>>>>>> I forgot to tell you something essential in using stream_vt. >>>>>>>>> The following interface for 'test' cannot work: >>>>>>>>> >>>>>>>>> fun test (acc: !$SBF.stringbuf, cs: llstring): stream_vt(DT) = >>>>>>>>> >>>>>>>>> What you need is >>>>>>>>> >>>>>>>>> fun test (acc: $SBF.stringbuf, cs: llstring): stream_vt(DT) = >>>>>>>>> >>>>>>>>> The 'acc' stringbuf needs to be consumed by 'test'. The >>>>>>>>> implementation >>>>>>>>> of 'test' looks like this: >>>>>>>>> >>>>>>>>> $ldelay >>>>>>>>> ( >>>>>>>>> <code for stream construction> >>>>>>>>> , >>>>>>>>> (freeing(acc); freeing(cs)) // this part is executed when the >>>>>>>>> stream is freed >>>>>>>>> ) >>>>>>>>> >>>>>>>>> On Mon, Mar 6, 2017 at 8:19 AM, August Alm <[email protected]> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> The points you mention are part of the reason I chose to wrote >>>>>>>>>> the csv lexer the way I did. It follows one of the fastests Haskell >>>>>>>>>> csv >>>>>>>>>> parsers, and I was curious to see how using linear types could >>>>>>>>>> optimize >>>>>>>>>> performance. >>>>>>>>>> >>>>>>>>>> Regarding your suggestion on how to make better use of $ldelay in >>>>>>>>>> my code: I'm stuck on a compiler error that I can't make sense of. >>>>>>>>>> The >>>>>>>>>> following pseudo-minimal example throws the same kind of errors: >>>>>>>>>> >>>>>>>>>> #include "share/atspre_define.hats" >>>>>>>>>> #include "share/atspre_staload.hats" >>>>>>>>>> staload UN = "prelude/SATS/unsafe.sats" >>>>>>>>>> staload SBF = "libats/SATS/stringbuf.sats" >>>>>>>>>> staload _(*SBF*) = "libats/DATS/stringbuf.dats" >>>>>>>>>> >>>>>>>>>> datatype DT = D_T of @{ alpha = char } >>>>>>>>>> vtypedef llstring = stream_vt(char) >>>>>>>>>> >>>>>>>>>> fun >>>>>>>>>> test (acc: !$SBF.stringbuf, cs: llstring): stream_vt(DT) >>>>>>>>>> = >>>>>>>>>> $ldelay >>>>>>>>>> ( case !cs of >>>>>>>>>> | ~stream_vt_nil() => >>>>>>>>>> if $SBF.stringbuf_get_size(acc) = i2sz(0) then >>>>>>>>>> stream_vt_nil() >>>>>>>>>> else stream_vt_cons(D_T(@{alpha = 'a'}), >>>>>>>>>> stream_vt_make_nil()) >>>>>>>>>> | ~stream_vt_cons(c, cs1) => >>>>>>>>>> let val crec = D_T(@{alpha = c}) >>>>>>>>>> in stream_vt_cons(crec, test(acc, cs1)) >>>>>>>>>> end >>>>>>>>>> , ~cs >>>>>>>>>> ) >>>>>>>>>> >>>>>>>>>> The compiler can not infer the type I want (which is >>>>>>>>>> [stream_vt_con(DT)] for the [stream_vt_nil()] following the first >>>>>>>>>> [then] in >>>>>>>>>> the function body. The error message says >>>>>>>>>> >>>>>>>>>> the dynamic expression cannot be assigned the type [S2EVar(5492)]. >>>>>>>>>> [...] mismatch of sorts in unification: >>>>>>>>>> The sort of variable is: S2RTbas(S2RTBASimp(1; t@ype)) >>>>>>>>>> The sort of solution is: S2RTbas(S2RTBASimp(2; viewtype)) >>>>>>>>>> [...] mismatch of static terms (tyleq): >>>>>>>>>> The actual term is: S2Eapp(S2Ecst(stream_vt_con); S2EVar(5495)) >>>>>>>>>> The needed term is: S2EVar(5492) >>>>>>>>>> >>>>>>>>>> (There are further errors of the same form.) Is the culprit that >>>>>>>>>> [stream_vt] of a nonlinear datatype requires some special care? The >>>>>>>>>> version >>>>>>>>>> with [stream_vt_make_nil()] instead of explicit [$ldelay] works so >>>>>>>>>> the >>>>>>>>>> error ought to be subtle. >>>>>>>>>> >>>>>>>>>> Best wishes, >>>>>>>>>> August >>>>>>>>>> >>>>>>>>>> Den söndag 5 mars 2017 kl. 23:58:35 UTC+1 skrev gmhwxi: >>>>>>>>>>> >>>>>>>>>>> Yes, you definitely got it :) >>>>>>>>>>> >>>>>>>>>>> Stream_vt is very memory-frugal. >>>>>>>>>>> >>>>>>>>>>> Haskell relies on deforestation (complex complier optimization) >>>>>>>>>>> to reduce memory usage of lazy evaluation. In ATS, deforestation >>>>>>>>>>> is >>>>>>>>>>> not supported. Instead, the programmer needs to recycle memory >>>>>>>>>>> explicitly. >>>>>>>>>>> >>>>>>>>>>> Compared to Haskell, corresponding code using stream_vt in ATS >>>>>>>>>>> can be >>>>>>>>>>> much more efficient both time-wise and memory-wise. >>>>>>>>>>> >>>>>>>>>>> For instance, the following example (for computing Mersenne >>>>>>>>>>> primes) can >>>>>>>>>>> run for days without run-time GC: >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> https://github.com/githwxi/ATS-Postiats/blob/master/doc/EXAMPLE/RosettaCode/Lucas-Lehmer_test2.dats >>>>>>>>>>> >>>>>>>>>>> It convincingly attests to the power of linear streams. >>>>>>>>>>> >>>>>>>>>>> Cheers! >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> On Sun, Mar 5, 2017 at 5:34 PM, August Alm <[email protected]> >>>>>>>>>>> wrote: >>>>>>>>>>> >>>>>>>>>>>> Thanks for the tip! I think I understand. I treated $ldelay >>>>>>>>>>>> much as a data constructor, so that all streams are equally lazy, >>>>>>>>>>>> whereas >>>>>>>>>>>> there are in fact many ways to sequence into thunks. Let me give >>>>>>>>>>>> an example >>>>>>>>>>>> to anchor the discussion. Both the following implementations of a >>>>>>>>>>>> map-template for linear streams typecheck: >>>>>>>>>>>> >>>>>>>>>>>> fun {a, b: t0ype} >>>>>>>>>>>> map_make_cons >>>>>>>>>>>> ( xs: stream_vt(a) >>>>>>>>>>>> , f: a -> b >>>>>>>>>>>> ) : stream_vt(b) = >>>>>>>>>>>> case !xs of >>>>>>>>>>>> | ~stream_vt_nil() => stream_vt_make_nil() >>>>>>>>>>>> | ~stream_vt_cons(x, xs1) => >>>>>>>>>>>> stream_vt_make_cons(f(x), map_make_cons(xs1, f)) >>>>>>>>>>>> >>>>>>>>>>>> fun {a, b: t0ype} >>>>>>>>>>>> map_ldelay >>>>>>>>>>>> ( xs: stream_vt(a) >>>>>>>>>>>> , f: a -> b >>>>>>>>>>>> ) : stream_vt(b) = >>>>>>>>>>>> $ldelay >>>>>>>>>>>> ( case !xs of >>>>>>>>>>>> | ~stream_vt_nil() => stream_vt_nil() >>>>>>>>>>>> | ~stream_vt_cons(x, xs1) => >>>>>>>>>>>> stream_vt_cons(f(x), map_ldelay(xs1, f)) >>>>>>>>>>>> , ~xs >>>>>>>>>>>> ) >>>>>>>>>>>> >>>>>>>>>>>> The second is maximally lazy. The first, [map_make_cons] is >>>>>>>>>>>> less lazy because checking the case-conditions is not delayed. My >>>>>>>>>>>> code was >>>>>>>>>>>> like the first example, only much more was going on inside the >>>>>>>>>>>> case >>>>>>>>>>>> expressions. Is that a correct assessment? >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> Den söndag 5 mars 2017 kl. 04:07:42 UTC+1 skrev gmhwxi: >>>>>>>>>>>>> >>>>>>>>>>>>> BTW, it seems you don't need to do much to fix the issue. >>>>>>>>>>>>> >>>>>>>>>>>>> Basically, you just do >>>>>>>>>>>>> >>>>>>>>>>>>> 1) Put the body of parse_entry into $ldelay(...) >>>>>>>>>>>>> 2) Change stream_vt_make_cons into stream_vt_cons >>>>>>>>>>>>> >>>>>>>>>>>>> There may be a few other things but they should all be >>>>>>>>>>>>> very minor. >>>>>>>>>>>>> >>>>>>>>>>>>> On Saturday, March 4, 2017 at 9:47:07 PM UTC-5, gmhwxi wrote: >>>>>>>>>>>>>> >>>>>>>>>>>>>> I took a glance at your code. >>>>>>>>>>>>>> >>>>>>>>>>>>>> I noticed a very common mistake involving the use of >>>>>>>>>>>>>> stream (or stream_vt). Basically, the way stream is used >>>>>>>>>>>>>> in your code is like the way list is used. This causes the >>>>>>>>>>>>>> stack issue you encountered. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Say that you have a function that returns a stream. In nearly >>>>>>>>>>>>>> all cases, the correct way to implement such a function should >>>>>>>>>>>>>> use the following style: >>>>>>>>>>>>>> >>>>>>>>>>>>>> fun foo(...): stream_vt(...) = $ldelay >>>>>>>>>>>>>> ( >>>>>>>>>>>>>> ... >>>>>>>>>>>>>> ) >>>>>>>>>>>>>> >>>>>>>>>>>>>> The idea is that 'foo' should return in O(1) time. The body >>>>>>>>>>>>>> of $ldelay >>>>>>>>>>>>>> is only evaluated with the first element of the returned >>>>>>>>>>>>>> stream is neede. >>>>>>>>>>>>>> Sometimes, this is call full laziness. Without full laziness, >>>>>>>>>>>>>> a stream may >>>>>>>>>>>>>> behave like a list, defeating the very purpose of using a >>>>>>>>>>>>>> stream. >>>>>>>>>>>>>> >>>>>>>>>>>>>> On Saturday, March 4, 2017 at 7:27:03 PM UTC-5, August Alm >>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> I've spent few hours trying to figure out how to make >>>>>>>>>>>>>>> proper use of npm and gave up--for now. If the project turns >>>>>>>>>>>>>>> into something >>>>>>>>>>>>>>> more serious (i.e., useful to others) then I will have another >>>>>>>>>>>>>>> go at it. >>>>>>>>>>>>>>> For now my naive attempts at making effective use of linear >>>>>>>>>>>>>>> streams can be >>>>>>>>>>>>>>> witnessed at GitHub: >>>>>>>>>>>>>>> https://github.com/August-Alm/ats_csv_lexer Any and all >>>>>>>>>>>>>>> comments on how to improve are appreciated. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> Best wishes, August. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> Den fredag 3 mars 2017 kl. 23:57:54 UTC+1 skrev gmhwxi: >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> One possibility is to build a npm package and then publish >>>>>>>>>>>>>>>> it. >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> If you go to https://www.npmjs.com/ and seach for >>>>>>>>>>>>>>>> 'atscntrb'. You can find >>>>>>>>>>>>>>>> plenty packages. You may need to install npm first. >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> If you do build a npm package, I suggest that you choose a >>>>>>>>>>>>>>>> name space for >>>>>>>>>>>>>>>> yourself. E.g., atscntrb-a?a-..., where ? is the first >>>>>>>>>>>>>>>> letter of your middle name. >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> On Fri, Mar 3, 2017 at 5:48 PM, August Alm < >>>>>>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> How would I best share larger code portions? I have no >>>>>>>>>>>>>>>>> concerns about my making my mistakes public, heh. >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> I believe everything is lazy as-is (all data is >>>>>>>>>>>>>>>>> [stream_vt("sometype")]). And I've tried to write >>>>>>>>>>>>>>>>> tail-recursive functional >>>>>>>>>>>>>>>>> code. The algorithm is based on two mutually recursing >>>>>>>>>>>>>>>>> functions, "fun ... >>>>>>>>>>>>>>>>> and ..", similar to how you did things in your csv-parser >>>>>>>>>>>>>>>>> (thanks for >>>>>>>>>>>>>>>>> pointing out that piece of code). However, I cannot set them >>>>>>>>>>>>>>>>> up with "fn* >>>>>>>>>>>>>>>>> .. and .." to enforce a local jump because they call each >>>>>>>>>>>>>>>>> other in a too >>>>>>>>>>>>>>>>> intertwined way. Might that be it? >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> Den fredag 3 mars 2017 kl. 23:32:15 UTC+1 skrev gmhwxi: >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> You are welcome! >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> Since I have not seen your code, I could only guess :) >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> Usually, what you described can be fixed by using >>>>>>>>>>>>>>>>>> tail-recursion, or >>>>>>>>>>>>>>>>>> by using lazy-evaluation. The former approach is >>>>>>>>>>>>>>>>>> straightforward. You >>>>>>>>>>>>>>>>>> just need to identify the function or functions that >>>>>>>>>>>>>>>>>> cause the deep stack >>>>>>>>>>>>>>>>>> usage. Then try to rewrite using tail-recursion. >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> On Fri, Mar 3, 2017 at 5:25 PM, August Alm < >>>>>>>>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>> Hi! >>>>>>>>>>>>>>>>>>> I had indeed made a logical error that caused any stream >>>>>>>>>>>>>>>>>>> with "carriage return" followed by "newline" to recurse >>>>>>>>>>>>>>>>>>> indefinitely. Thank >>>>>>>>>>>>>>>>>>> you for your patience and pedagogical instincts, Professor! >>>>>>>>>>>>>>>>>>> There is still >>>>>>>>>>>>>>>>>>> some issue though, one that I believe is more subtle. I >>>>>>>>>>>>>>>>>>> fixed the logical >>>>>>>>>>>>>>>>>>> error and my algorithm now handles all the test cases you >>>>>>>>>>>>>>>>>>> suggested. >>>>>>>>>>>>>>>>>>> However, when fed an actual CSV-file with a thousand rows >>>>>>>>>>>>>>>>>>> and about 300 >>>>>>>>>>>>>>>>>>> columns it still segfaults--unless I manually increase the >>>>>>>>>>>>>>>>>>> stack space on >>>>>>>>>>>>>>>>>>> my computer! I don't know exactly where the critical limit >>>>>>>>>>>>>>>>>>> is, but >>>>>>>>>>>>>>>>>>> increasing it from 8192 kbytes to 65536 certainly did the >>>>>>>>>>>>>>>>>>> trick. The whole >>>>>>>>>>>>>>>>>>> file parsed without problem, and rather quickly at that. It >>>>>>>>>>>>>>>>>>> seems my >>>>>>>>>>>>>>>>>>> algorithm makes too much use of stack allocation and that I >>>>>>>>>>>>>>>>>>> may have to >>>>>>>>>>>>>>>>>>> rethink some of my (would-be) optimization choices. >>>>>>>>>>>>>>>>>>> Best wishes, >>>>>>>>>>>>>>>>>>> August >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>> Den fredag 3 mars 2017 kl. 15:22:00 UTC+1 skrev gmhwxi: >>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>> Now you may do the following tests: >>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>> Try: >>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>> val ins = streamize_string_char("a;b") // should work >>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>> Try: >>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>> val ins = streamize_string_char("a;b\n") // may not work >>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>> Try: >>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>> val ins = streamize_string_char("a;b\015\012") // >>>>>>>>>>>>>>>>>>>> should cause crash >>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>> On Thursday, March 2, 2017 at 9:21:21 PM UTC-5, gmhwxi >>>>>>>>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> When tried, I saw the following 5 chars (ascii) in >>>>>>>>>>>>>>>>>>>>> small.csv: >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> 97 >>>>>>>>>>>>>>>>>>>>> 59 >>>>>>>>>>>>>>>>>>>>> 98 >>>>>>>>>>>>>>>>>>>>> 13 >>>>>>>>>>>>>>>>>>>>> 10 >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> My testing code: >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> #include"share/atspre_staload.hats" >>>>>>>>>>>>>>>>>>>>> #include"share/HATS/atspre_staload_libats_ML.hats" >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> implement main0 () = { >>>>>>>>>>>>>>>>>>>>> val inp = fileref_open_exn("small.csv", file_mode_r) >>>>>>>>>>>>>>>>>>>>> val ins = streamize_fileref_char(inp) >>>>>>>>>>>>>>>>>>>>> val ins = stream2list_vt(ins) >>>>>>>>>>>>>>>>>>>>> val ins = g0ofg1(list_vt2t(ins))97 >>>>>>>>>>>>>>>>>>>>> val ( ) = println! ("length(ins) = ", length(ins)) >>>>>>>>>>>>>>>>>>>>> val ( ) = (ins).foreach()(lam c => >>>>>>>>>>>>>>>>>>>>> println!(char2int0(c))) >>>>>>>>>>>>>>>>>>>>> (* >>>>>>>>>>>>>>>>>>>>> val lexed = lex_csv(true, ';', ins) >>>>>>>>>>>>>>>>>>>>> *) >>>>>>>>>>>>>>>>>>>>> val () = fileref_close(inp) >>>>>>>>>>>>>>>>>>>>> (* >>>>>>>>>>>>>>>>>>>>> val h = (lexed.head()) >>>>>>>>>>>>>>>>>>>>> val- CSV_Field(r) = h >>>>>>>>>>>>>>>>>>>>> val a = r.csvFieldContent >>>>>>>>>>>>>>>>>>>>> val () = println!(a) >>>>>>>>>>>>>>>>>>>>> *) >>>>>>>>>>>>>>>>>>>>> } >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> On Thu, Mar 2, 2017 at 9:13 PM, August Alm <...> >>>>>>>>>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> Just "a;b", or? (Attached.) >>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> Den fredag 3 mars 2017 kl. 03:03:08 UTC+1 skrev >>>>>>>>>>>>>>>>>>>>>> gmhwxi: >>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>> I suspect that the file you used contains other >>>>>>>>>>>>>>>>>>>>>>> characters. >>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>> What is in "small.csv"? >>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>> On Thu, Mar 2, 2017 at 8:52 PM, August Alm <...> >>>>>>>>>>>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> The file compiles (I've tried a few compiler >>>>>>>>>>>>>>>>>>>>>>>> options) and "gdb run" yields >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> Program received signal SIGSEGV, Segmentation >>>>>>>>>>>>>>>>>>>>>>>> fault. >>>>>>>>>>>>>>>>>>>>>>>> 0x00007ffff783eea5 in _int_malloc >>>>>>>>>>>>>>>>>>>>>>>> (av=0x7ffff7b6a620 <main_arena>, bytes=16) at >>>>>>>>>>>>>>>>>>>>>>>> malloc.c:3790 >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> The frames 0-3 involve allocation functions that >>>>>>>>>>>>>>>>>>>>>>>> are not particular to my file. Frame 4 says: >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> #4 __patsfun_28__28__14 (arg0=<optimized out>, >>>>>>>>>>>>>>>>>>>>>>>> env1=0x605540, env0=10 '\n') at csv_lexer_dats.c:9023 >>>>>>>>>>>>>>>>>>>>>>>> 9023 ATSINSmove_con1_new(tmpret63__14, >>>>>>>>>>>>>>>>>>>>>>>> postiats_tysum_7) ; >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> My not-so-educated guess is that this refers to >>>>>>>>>>>>>>>>>>>>>>>> making a cons-cell of a stream. >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> But: How can my function do just fine when manually >>>>>>>>>>>>>>>>>>>>>>>> fed >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> cons('a', cons( ';', sing('b'))): >>>>>>>>>>>>>>>>>>>>>>>> stream_vt(char), >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> but segfault when I use [streamize_fileref_char] to >>>>>>>>>>>>>>>>>>>>>>>> construct the very same stream from the string "a;b" >>>>>>>>>>>>>>>>>>>>>>>> in a file? Where is >>>>>>>>>>>>>>>>>>>>>>>> the room for an infinite recursion in that? >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> Thank you, >>>>>>>>>>>>>>>>>>>>>>>> August >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> Den torsdag 2 mars 2017 kl. 23:04:35 UTC+1 skrev >>>>>>>>>>>>>>>>>>>>>>>> August Alm: >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> Hi! >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> I'm in over my head and tried writing a CSV-parser >>>>>>>>>>>>>>>>>>>>>>>>> using linear lazy streams. My code thus far is 600 >>>>>>>>>>>>>>>>>>>>>>>>> lines and almost to my >>>>>>>>>>>>>>>>>>>>>>>>> own surprise I get it to compile! However, there is >>>>>>>>>>>>>>>>>>>>>>>>> something fishy because >>>>>>>>>>>>>>>>>>>>>>>>> I get a segfault when applying my program to an >>>>>>>>>>>>>>>>>>>>>>>>> actual CSV-file. I've been >>>>>>>>>>>>>>>>>>>>>>>>> trying to debug using gdb but the fault eludes me. >>>>>>>>>>>>>>>>>>>>>>>>> Since I don't expect >>>>>>>>>>>>>>>>>>>>>>>>> anyone to mull through 600 lines of code, I am hoping >>>>>>>>>>>>>>>>>>>>>>>>> these code snippets >>>>>>>>>>>>>>>>>>>>>>>>> are enough for one of you guys to give me some advice. >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> This code executes just fine: >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> implement main0 () = { >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> val test = stream_vt_make_cons( >>>>>>>>>>>>>>>>>>>>>>>>> 'a', >>>>>>>>>>>>>>>>>>>>>>>>> stream_vt_make_cons( >>>>>>>>>>>>>>>>>>>>>>>>> ';', >>>>>>>>>>>>>>>>>>>>>>>>> stream_vt_make_sing('b'))) (* the stream >>>>>>>>>>>>>>>>>>>>>>>>> ('a', ';', 'b') *) >>>>>>>>>>>>>>>>>>>>>>>>> val lexed = lex_csv(true, ';', test) >>>>>>>>>>>>>>>>>>>>>>>>> val h = (lexed.head()) >>>>>>>>>>>>>>>>>>>>>>>>> val- CSV_Field(r) = h >>>>>>>>>>>>>>>>>>>>>>>>> val a = r.csvFieldContent >>>>>>>>>>>>>>>>>>>>>>>>> val () = println!(a) >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> } >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> Here [lex_csv] is my 600-line alogrithm. It reads >>>>>>>>>>>>>>>>>>>>>>>>> a [stream_vt(char)] and gives back a >>>>>>>>>>>>>>>>>>>>>>>>> [stream_vt(CSVEntry)], where >>>>>>>>>>>>>>>>>>>>>>>>> [CSVEntry] is a record type, one of whose fields is >>>>>>>>>>>>>>>>>>>>>>>>> [CSVFieldContent]. When >>>>>>>>>>>>>>>>>>>>>>>>> executing the program I get "a" printed to the >>>>>>>>>>>>>>>>>>>>>>>>> console. >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> This code results in a segfault: >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> implement main0 () = { >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> val inp = fileref_open_exn("small.csv", >>>>>>>>>>>>>>>>>>>>>>>>> file_mode_r) >>>>>>>>>>>>>>>>>>>>>>>>> val ins = streamize_fileref_char(inp) >>>>>>>>>>>>>>>>>>>>>>>>> val lexed = lex_csv(true, ';', ins) >>>>>>>>>>>>>>>>>>>>>>>>> val () = fileref_close(inp) >>>>>>>>>>>>>>>>>>>>>>>>> val h = (lexed.head()) >>>>>>>>>>>>>>>>>>>>>>>>> val- CSV_Field(r) = h >>>>>>>>>>>>>>>>>>>>>>>>> val a = r.csvFieldContent >>>>>>>>>>>>>>>>>>>>>>>>> val () = println!(a) >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> } >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> The file "small.csv" only contains the string >>>>>>>>>>>>>>>>>>>>>>>>> "a;b". Hence I would expect this code to give the >>>>>>>>>>>>>>>>>>>>>>>>> result as the previous >>>>>>>>>>>>>>>>>>>>>>>>> one! But, it doesn't just return something else, it >>>>>>>>>>>>>>>>>>>>>>>>> segfaults. >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> gdb indicates there is a malloc problem having to >>>>>>>>>>>>>>>>>>>>>>>>> do with "GC_clear_stack_inner", in case that's >>>>>>>>>>>>>>>>>>>>>>>>> helpful. (I'm a >>>>>>>>>>>>>>>>>>>>>>>>> mathematician who recently left academia after >>>>>>>>>>>>>>>>>>>>>>>>> postdoc and decided to teach >>>>>>>>>>>>>>>>>>>>>>>>> myself programming to become more useful outside of >>>>>>>>>>>>>>>>>>>>>>>>> academia; hence I >>>>>>>>>>>>>>>>>>>>>>>>> understand type systems and the like--the mathy >>>>>>>>>>>>>>>>>>>>>>>>> stuff--a lot better than I >>>>>>>>>>>>>>>>>>>>>>>>> understand memory allocation and other stuff that >>>>>>>>>>>>>>>>>>>>>>>>> most programmers are >>>>>>>>>>>>>>>>>>>>>>>>> supposed to be confident with.) >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> What could be the problem here? >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> Best wishes, >>>>>>>>>>>>>>>>>>>>>>>>> August >>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>> -- >>>>>>>>>>>>>>>>>>>>>>>> You received this message because you are >>>>>>>>>>>>>>>>>>>>>>>> subscribed to the Google Groups "ats-lang-users" group. >>>>>>>>>>>>>>>>>>>>>>>> To unsubscribe from this group and stop receiving >>>>>>>>>>>>>>>>>>>>>>>> emails from it, send an email to >>>>>>>>>>>>>>>>>>>>>>>> [email protected]. >>>>>>>>>>>>>>>>>>>>>>>> To post to this group, send email to >>>>>>>>>>>>>>>>>>>>>>>> [email protected]. >>>>>>>>>>>>>>>>>>>>>>>> Visit this group at >>>>>>>>>>>>>>>>>>>>>>>> https://groups.google.com/group/ats-lang-users. >>>>>>>>>>>>>>>>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>>>>>>>>>>>>>>> https://groups.google.com/d/msgid/ats-lang-users/69535c5c-eac3-472c-bb39-062ad4708a72%40googlegroups.com >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>> <https://groups.google.com/d/msgid/ats-lang-users/69535c5c-eac3-472c-bb39-062ad4708a72%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>>>>>>>>>>>>>>>>> . >>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>> -- >>>>>>>>>>>>>>>>>>>>>> You received this message because you are subscribed >>>>>>>>>>>>>>>>>>>>>> to the Google Groups "ats-lang-users" group. >>>>>>>>>>>>>>>>>>>>>> To unsubscribe from this group and stop receiving >>>>>>>>>>>>>>>>>>>>>> emails from it, send an email to >>>>>>>>>>>>>>>>>>>>>> [email protected]. >>>>>>>>>>>>>>>>>>>>>> To post to this group, send email to >>>>>>>>>>>>>>>>>>>>>> [email protected]. >>>>>>>>>>>>>>>>>>>>>> Visit this group at >>>>>>>>>>>>>>>>>>>>>> https://groups.google.com/group/ats-lang-users. >>>>>>>>>>>>>>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>>>>>>>>>>>>> https://groups.google.com/d/msgid/ats-lang-users/e608c7bb-42ce-457b-a606-9fe3525f801d%40googlegroups.com >>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> <https://groups.google.com/d/msgid/ats-lang-users/e608c7bb-42ce-457b-a606-9fe3525f801d%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>>>>>>>>>>>>>>> . >>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>> -- >>>>>>>>>>>>>>>>>>> You received this message because you are subscribed to >>>>>>>>>>>>>>>>>>> the Google Groups "ats-lang-users" group. >>>>>>>>>>>>>>>>>>> To unsubscribe from this group and stop receiving emails >>>>>>>>>>>>>>>>>>> from it, send an email to >>>>>>>>>>>>>>>>>>> [email protected]. >>>>>>>>>>>>>>>>>>> To post to this group, send email to >>>>>>>>>>>>>>>>>>> [email protected]. >>>>>>>>>>>>>>>>>>> Visit this group at >>>>>>>>>>>>>>>>>>> https://groups.google.com/group/ats-lang-users. >>>>>>>>>>>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>>>>>>>>>> https://groups.google.com/d/msgid/ats-lang-users/34dfad01-9bd4-464f-9ccd-6dfae8207f4c%40googlegroups.com >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>> <https://groups.google.com/d/msgid/ats-lang-users/34dfad01-9bd4-464f-9ccd-6dfae8207f4c%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>>>>>>>>>>>> . >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> -- >>>>>>>>>>>>>>>>> You received this message because you are subscribed to >>>>>>>>>>>>>>>>> the Google Groups "ats-lang-users" group. >>>>>>>>>>>>>>>>> To unsubscribe from this group and stop receiving emails >>>>>>>>>>>>>>>>> from it, send an email to >>>>>>>>>>>>>>>>> [email protected]. >>>>>>>>>>>>>>>>> To post to this group, send email to >>>>>>>>>>>>>>>>> [email protected]. >>>>>>>>>>>>>>>>> Visit this group at >>>>>>>>>>>>>>>>> https://groups.google.com/group/ats-lang-users. >>>>>>>>>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>>>>>>>> https://groups.google.com/d/msgid/ats-lang-users/c2f9d2b7-61f5-4142-b8b2-930147ee589d%40googlegroups.com >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> <https://groups.google.com/d/msgid/ats-lang-users/c2f9d2b7-61f5-4142-b8b2-930147ee589d%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>>>>>>>>>> . >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> -- >>>>>>>>>>>> You received this message because you are subscribed to the >>>>>>>>>>>> Google Groups "ats-lang-users" group. >>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from >>>>>>>>>>>> it, send an email to [email protected]. >>>>>>>>>>>> To post to this group, send email to >>>>>>>>>>>> [email protected]. >>>>>>>>>>>> Visit this group at >>>>>>>>>>>> https://groups.google.com/group/ats-lang-users. >>>>>>>>>>>> To view this discussion on the web visit >>>>>>>>>>>> https://groups.google.com/d/msgid/ats-lang-users/d78409e2-aff1-4b96-98f3-eb3a5d20ff95%40googlegroups.com >>>>>>>>>>>> >>>>>>>>>>>> <https://groups.google.com/d/msgid/ats-lang-users/d78409e2-aff1-4b96-98f3-eb3a5d20ff95%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>>>>> . >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>> You received this message because you are subscribed to the >>>>>>>>>> Google Groups "ats-lang-users" group. >>>>>>>>>> To unsubscribe from this group and stop receiving emails from it, >>>>>>>>>> send an email to [email protected]. >>>>>>>>>> To post to this group, send email to [email protected]. >>>>>>>>>> Visit this group at >>>>>>>>>> https://groups.google.com/group/ats-lang-users. >>>>>>>>>> To view this discussion on the web visit >>>>>>>>>> https://groups.google.com/d/msgid/ats-lang-users/716c8c61-d535-412d-8584-d4030d20801d%40googlegroups.com >>>>>>>>>> >>>>>>>>>> <https://groups.google.com/d/msgid/ats-lang-users/716c8c61-d535-412d-8584-d4030d20801d%40googlegroups.com?utm_medium=email&utm_source=footer> >>>>>>>>>> . >>>>>>>>>> >>>>>>>>> >>>>>>>>> -- >> You received this message because you are subscribed to the Google Groups >> "ats-lang-users" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected] <javascript:>. >> To post to this group, send email to [email protected] >> <javascript:>. >> Visit this group at https://groups.google.com/group/ats-lang-users. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/ats-lang-users/f19d1d97-1aa7-40a2-83e3-d779c3f674b8%40googlegroups.com >> >> <https://groups.google.com/d/msgid/ats-lang-users/f19d1d97-1aa7-40a2-83e3-d779c3f674b8%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > > -- You received this message because you are subscribed to the Google Groups "ats-lang-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/ats-lang-users. To view this discussion on the web visit https://groups.google.com/d/msgid/ats-lang-users/d38dfda3-e1f5-4633-a6ae-ef6274e95fb3%40googlegroups.com.
