Re: [q-lang-users] Just starting with Q
Brought to you by:
agraef
From: Albert G. <Dr....@t-...> - 2006-08-24 03:40:31
|
Hi Burton, thanks for the log, that cleared things up quite a bit. Looks like the computations are going ok now -- no more unevaluated cat applications, so I assume that these were actually due to the bug in 7.1/7.2 I mentioned, which is now fixed. But there are various bugs in your script which cause the behaviour that you see with --no-prelude. The bugs you were bitten by are not unusual, and I have some advice on how to avoid these pitfalls. Specifically, it might be a good idea to run your scripts with -w which warns you about function symbols that are used but neither defined (occurring on the lhs of an equation) nor explicitly declared anywhere. (There's also --pedantic a.k.a. -w2 which warns you about all function and free variable symbols which are not explicitly declared, but that's rather awkward since it forces you to declare each and every symbol.) I have my Emacs Q mode configured to always run the interpreter with -w, and of course you can also do the same on the command line with an alias. Running your script with --no-prelude -w gives: Warning cat, line 10: undeclared function symbol `issym' Warning cat, line 10: undeclared function symbol `prints' Warning cat, line 10: undeclared function symbol `putc' Warning cat, line 10: undeclared function symbol `fgetc' (The warnings are printed at the end of a script, that's why you always see line 10 up there. With --pedantic you get the warnings on the spot, for each first occurrence of an undeclared symbol.) Ok, so issym and prints aren't defined anywhere, but these are not the culprits here. But putc/fgetc are not defined either and this breaks your script with --no-prelude. These functions come from clib.q, and actually they are just aliases for writec/freadc, so replacing these for putc/fgetc will make the cat function work as intended, even with --no-prelude. BTW, this kind of bugs is rather symptomatic of Q, because function symbols are declared implicitly, and Q is perfectly happy with applications of undefined or partially defined functions; they're just normal forms. This is actually an essential feature of Q as a term rewriting language. In a more conventional language like Lisp or Haskell such bugs cause runtime or compile time errors. In Q, they can mostly be avoided with -w. Not always; Q is a sharp knife. ;-) More subtle problems which cannot be caught with -w/--pedantic have to do with Q's dynamic typing and unbounded ad-hoc polymorphism; there's no way to warn about these without severely restricting Q's expressiveness, so you'll have to resort to the debugger or unit tests to find them. Burton Samograd wrote: > [lots of debugger output snipped] > # just hangs here, and I have to hit ctl-c > <9> [~/.q] .Wed Aug 23 16:50:18. > q cat --no-prelude -d -c 'cat2 (fopen "cat" "r")' > ** fopen "cat" "r" ==> <<File>> > 0> cat, line 8: cat2 <<File>> ==> () if feof <<File>> > (type ? for help) > : c > cat F:String = cat_file (fopen F "r"); > C-c C-c! Break > >>>>cat2 (fopen "cat" "r") ^ > > # hangs here too So what happened here was that with --no-prelude fgetc never read anything, because it wasn't defined, hence feof never became true, and the cat function looped without actually doing anything else. And you saw the same symptom with the second definition, because in the second equation for cat2 you didn't recursively call cat2, but the flawed cat function. After fixing that cat2 worked ok for me. Just for the record, here is the corrected script: cat F:String = cat_file (fopen F "r"); cat F:File = cat_file F; cat F = cat_file (fopen (str F) "r") if issym F; = prints "cat: unsupported type"; cat_file F:File = () if feof F; = writec (freadc F) || cat F otherwise; cat2 F = () if feof F; = writes (freads F) || writes "\n" || cat2 F otherwise; (Well, obviously you still have to define prints somewhere, and copy the definition of issym from the standard library script typec.q if you want to run the script with --no-prelude.) BTW, another way to copy a text file, for the lazy programmer, is to use clib::fget which slurps an entire file in at once and returns it as a string. E.g.: 'cat F = fputs (fget F);'. There are also various low-level I/O functions in clib which allow arbitrary (possibly binary) files to be read and written in big chunks. Cheers, Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |