My teacher keeps drilling into our collective heads that using the break command is harmful, and that if we wish to terminate a loop early it would be far better to create a boolean variable, set it to 0, and add a condition to the head of the loop, and set the boolean variable to 1 when a break is needed. Note that this way you actually have to check this every single loop (where it is not needed almost every time) as well as waste a command to reset the boolean in case it was set to true.
It's about source code clarity. Ensuring loops and functions have only one entry point and only one exit point keeps control flow simple and lessens the risk of introducing bugs when modifying the code.
It's the kind of rule that you're likely to see in large projects where it's expected someone else will have to do maintenance on your code years after you've left the company.
Name:
Anonymous2011-05-30 13:16
Hilarious, it must suck being taught by such a fucking idiot. At least they're not a women.
>>10
You could abstract the second clause in the for(;;) to be divisor <= number/divisor
Name:
Anonymous2011-05-30 13:35
Use goto.
Name:
Anonymous2011-05-30 13:35
>>12
And let's say that I wanted do what is sometimes called "method abstraction".
Using boolean values, it would be hard to tell if the method should be called divisor() or isPrime(). Whereas if I re-wrote this looping using a break statement, I could pretty much tell right away that the method would be called isPrime().
>>1
Yes. Break is harmful. You should read SICP and use continuations instead of loops with break/continue.
Name:
Anonymous2011-05-30 16:35
>>16
No. SICP is harmful. You should use break and continue instead of Lisp faggotry.
Name:
Anonymous2011-05-30 16:42
>>17
Young man, you have learned a little bit and think you knows it all, but soon you will grow out of your sophomoric sophistication and come to realize that the world is more complicated, and you will begin again to understand that LISP is The Right Thing.
>>21
Consider me an ignorant barbarian for a moment (because I largely am when it comes to LISP), and explain to me the virtues and advantages of macros.
>>16-23
But Scheme has break and continue! They are called call-with-current-continuation! This should be portable R6RS code, but it is untested (define-syntax while
(lambda (stx)
(syntax-case stx ()
((while cond body body+ ...)
(with-syntax ((break (datum->syntax #'body 'break))
(continue (datum->syntax #'body 'continue)))
#'(let loop ()
(call-with-current-continuation
(lambda (break)
(let loop ()
(when cond
(call-with-current-continuation
(lambda (continue)
body body+ ...))
(loop)))))))))))
Yes, continue does the right thing in for (executes incr).
If you had read your SICP today, you would've known. You also would known that all the call-with-current-continuations can be optimized to call-with-escape-continuations.
>>26
They are all call-with-escape-continuation. That may be implemented with CL's block+return-from too (same concept).
(define-syntax for/break-at
(syntax-rules ()
((_ name init cond body . rest)
(call-with-current-continuation
(lambda (name) (for init cond body . rest))))))
;; short one
(define-syntax-rule (for/break-at n . rest)
(let/ec n (for . rest)))
(for/break-at il (set! ii 0) (< ii 1000) (inc! ii)
(for/break-at jl (set! jj 0) (< jj 1000) (inc! jj)
(for/break-at kl (set! kk 0) (< kk 1000) (inc! kk)
(when break? (il)))))
It looks bad, though, but that's because I'm just forcing C-style for into Scheme.
>>31
Also, an implementation of CL's tagbody (not exactly, same semantics, different syntax) in Racket, but it should be easily portable to R6RS too:
(define-syntax-parameter goto
(lambda (stx)
(raise-syntax-error 'goto (if (identifier? stx) "bad syntax" "bad syntax (not inside a tagbody)") stx)))
(let ((val #f))
(tagbody
(start
(set! val 1)
(goto point-a)
(inc! val 16))
(point-c
(inc! val 4)
(goto point-b)
(inc! val 32))
(point-a
(inc! val 2)
(goto point-c)
(inc! val 64))
(point-b
(inc! val 8)))
val)
; 15
Really, more languages should provide some non-local exit mechanism, and not in the form of exceptions.
Name:
Anonymous2011-05-30 18:04
>>23
Macro systems have a range of uses. Being able to choose the order of evaluation (see lazy evaluation and non-strict functions) enables the creation of new syntactic constructs (e.g. control structures) indistinguishable from those built into the language. For instance, in a Lisp dialect that has cond but lacks if, it is possible to define the latter in terms of the former using macros.
Next, macros make it possible to define data languages that are immediately compiled into code, which means that constructs such as state machines can be implemented in a way that is both natural and efficient.[8]
Macros can also be used to introduce new binding constructs. The most well-known example is the transformation of let into the application of a function to a set of arguments.
Felleisen conjectures[9] that these three categories make up the primary legitimate uses of macros in such a system.
>>25
That's pretty much the situation. Could you explain why the first is considered bad by some? Is it more or less what >>6 said, or is there a more mechanical reason?
>>32
And try-catch-finally-style exceptions:
And this, >>23, is why macros and continuations are important: I, alone, in less than one hour, have written what takes ages in other languages.
(define exception-handler
(make-parameter (lambda (x) (error "uncaught exception:" x))))
>>30
For every numeric type, C has 0 is false and everything else is true. >>31
This is cool beans. I wish I knew more lisps ;_;
Name:
Anonymous2011-05-30 19:02
>>36
That code sucks in terms of trying to get your point across.
Name:
Anonymous2011-05-30 19:04
>>24
You get a F for the lame attempt at an explanation. Ever hear of being concise and to the point you retard? Given that long and verbose shit code, I bet not.
>>39
You don't understand, that is(should be) PORTABLE (R6RS) Scheme code. It may be the first and last time you'll ever see such kind of Scheme code for the rest of your life. See >>28 for the unportable, fast, do-what-I-mean, properly (un)hygienic version.
Name:
Anonymous2011-05-30 19:17
>>41
It's incoherent gibberish. Again, you get the big fat F for trying to be clear and concise.
>>42 I can't read it and feel offended by someone that knows something that I don't know and don't like.
Well, it's not my fault if you didn't read your SICP.
Name:
Anonymous2011-05-30 19:34
>>43
Why? So I can end up like a shigt manager at taco bell like you?
>>44
We don't even have taco bell here, we're not inferior murricans, we don't need cheap fast ````food'''' (now with 80% of real meat less) to live. Enjoy living in a decading shitty country that thinks it's the center of the universe while the world moves on. Also, enjoy being an ignorant cretin basement dweller that will never even be employed at your precious taco bell and will die alone with no family and offspring.
>>44
Also go back to /g/, we don't like having fucking retarded idiots that just hate something with no fucking logical reason besides not understanding/not liking it.
Name:
Anonymous2011-05-30 19:45
>>45
I work as a Java Programmer for Kodak Gallery here in Emeryville, California.
>>47
Good for you, code monkey. Back to typing now. Make sure to catch all your exceptions.
>>49
You lack either reading comprehension or sense of humor.
>>48
I don't have time to play with you today. I'll just say that only syntax-e, datum->syntax, quote-syntax and define-syntax are required. In CL, quote, defmacro, define-symbol-macro and gensym are required. 4 definitions, 4 definitions. Go away.
>>57
Important: Although define-macro is non-hygienic, it is still restricted by Racket’s phase separation rules. This means that a macro cannot access run-time bindings, because it is executed in the syntax-expansion phase. Translating code that involves define-macro or defmacro from an implementation without this restriction usually implies separating macro related functionality into a begin-for-syntax or a module (that will be imported with require-for-syntax) and properly distinguishing syntactic information from run-time information.
The main problem with Racket's macro system (and with other syntax-case systems) is that instead of raw s-expressions you're dealing with syntax objects. This becomes very ugly when identifiers are handled: instead of dealing with plain symbols, you're dealing with these syntax values (called “identifiers” in this case) that are essentially a symbol and some opaque information that represents the lexical scope for its source. In several syntax-case systems this is the only difference from defmacro macros, but in the Racket case this applies to everything — identifiers, numbers, other immediate constants, and even function applications, etc — they are all wrapped.
>>66
I don't think I understood, you want the information both for compile-time inner macros inside the custom-defun and runtime? Provide it for both.
Name:
Anonymous2011-05-30 20:55
>>69
restricted by Racket’s phase separation rules. This means that a macro cannot access run-time bindings
Name:
Anonymous2011-05-30 20:55
The op never mentioned a fucking thing about a lisp dialect. The fact that you retards have managed to convert it to one makes you a morons. Now I see why you all work shit hourly jobs.
Name:
Anonymous2011-05-30 20:56
>>1
I occasionally come across code written in this style. It's harder to read since you don't get the "get out of the loop NOW" effect of a break statement, and what would otherwise be code that simply follows the break now turns into the body of another conditional. Trying to replace multiple breaks in a loop with booleans gets even more hairy. The efficiency implications are similarly obvious.
The only situation in which it could be considered more readable would be to a (very dumb) decompiler.
(defun f () (this-function))
(f)reference to undefined identifier: Sorry stdin::5: unquote: not in quasiquote in: (unquote I) reference to undefined identifier: misread stdin::16: unquote: not in quasiquote in: (unquote (define current-function (make-parameter #f))) reference to undefined identifier: define-syntax-rule stdin::160: application: bad syntax in: (defun f args . body) reference to undefined identifier: defun
>>88 syntax-case is r6rs standard, (define-syntax (head . args) . body) is a widespread extension to define-syntax, (define-syntax-rule (f . pat) . body) is sugar for (define-syntax f (syntax-rules () (pat . body))), make-parameter and parameterize are R6RS, R7RS and SRFI-I-don't-remember, object-name is non-standard.
Name:
Anonymous2011-05-30 21:29
>>91
That is why I love CL. It's so much simplier!
>>92
CLISP has its own non-standard extensions, SBCL has its own non-standard extensions, ClozureCL has its own non-standard extensions. Racket is a language derived from Scheme, use a r5rs-by-default implementation like Chicken.
>>93 CLISP has its own non-standard extensions, SBCL has its own non-standard extensions...
...but only Scheme/Racket manages to make a whole new language from extensions!
Name:
Anonymous2011-05-30 23:19
>>95
Macro in LISP.
(defmacro aif (cond then else)
`(let ((it ,cond))
(if it ,then ,else)))
"Macro" in Scheme/Racket.
#lang racket
(require racket/stxparam)
(define-syntax-parameter it (lambda (stx) (raise-syntax-error 'anaphora "missed context" stx)))
(define-syntax-rule (aif cond then else)
(let ([temp cond])
(syntax-parameterize ([it (make-rename-transformer #`temp)])
(if temp then else))))
>>35
it uses goto which is by some considered bad. Why? Goto makes programs harder to read and analyze.
also, why not just:
for(int ii=0; ii<1000; ii++) {
for(int jj=0; jj<1000; jj++) {
for(int kk=0; kk<1000; kk++) {
if(wantToBreak) {
kk=1000;
jj=1000;
ii=1000;
}
}
}
}
"breaks" from nested loops without the need of defining extra variable / checking it every loop
>>36
The guy who asked the question here. I guess I'll actually need to learn some LISP to figure what is up with that code, but regardles of that I thank you for the attempt.
Name:
Anonymous2011-05-31 3:45
>>102
Your C/C++ indendation is horrible! Use something like:
for (int ii=0
;ii<1000
;ii++)
{for (int jj=0
;jj<1000
;jj++)
{for (int kk=0
;kk<1000
;kk++)
{if (wantToBreak)
{kk=1000;
jj=1000;
ii=1000;}}}}
>>102
Changing the loop variable is argued by some to be even less readable. It's also rather stupid performance-wise, since you're forcing a comparison and I doubt the compiler would be able to replace that with a single jump (feel free to prove me wrong on this).
>>108 I doubt the compiler would be able to replace that with a single jump (feel free to prove me wrong on this).
Let's try!
[/prog/ 0]=> cat goto.c
#include <stdio.h>
main(){int i,j,k;
for(i=0;i++<1000;)
for(j=0;j++<1000;)
for(k=0;k++<1000;)
if(i==j==k==500)goto breakall;
else printf("%d:%d:%d",i,j,k);
breakall: return 0;}
[/prog/ 0]=> cat faggot.c
#include <stdio.h>
main(){int i,j,k;
for(i=0;i++<1000;)
for(j=0;j++<1000;)
for(k=0;k++<1000;)
if(i==j==k==500)i=j=k=1000;
else printf("%d:%d:%d",i,j,k);
return 0;}
[/prog/ 0]=> gcc -O3 goto.c -S
[/prog/ 0]=> gcc -O3 faggot.c -S
[/prog/ 0]=> diff -u goto.s faggot.s
--- goto.s 2011-05-31 14:41:25.000000000 +0200
+++ faggot.s 2011-05-31 14:41:30.000000000 +0200
@@ -1,4 +1,4 @@
- .file "goto.c"
+ .file "faggot.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d:%d:%d"
@@ -46,7 +46,6 @@
addl $1, %edi
cmpl $1001, %edi
jne .L2
-.L7:
leal -12(%ebp), %esp
xorl %eax, %eax
popl %ebx
Same with -O2, -O1 e no optimization flag. I didn't expect gcc to be this smart, actually.
Clang with no optimization, instead, sets them to 1000, and optimizes to a jmp in -O1.
[/prog/ 1]=> gcc --version
gcc (GCC) 4.6.0 20110513 (prerelease)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>>114
I don't see any fputs call in >>109, stop trolling.
Name:
Anonymous2011-05-31 14:37
>>115
The comment was made in respond number 111 you fucking retard. Again, do you have ADD? Are you Jewish? Are you a jew with ADD? If so, then HCN might be for you!