Cast aside your crutches.
Tyranny is global and local only, with no access to either the lexical or dynamic environment.
Show me an example.
I was thinking of python before python 3 when they added nonlocal. (I'm not really familiar with dynamic scoping so...)
Python nonlocal allows us to explicitly choose scope behavior in nested function definitions.
def outer():
x = 1
def inner():
x = 2
print(x)
inner()
print(x)
def outer_nl():
x = 1
def inner():
nonlocal x
x = 2
print(x)
inner()
print(x)
outer() # 2 1
outer_nl() # 2 2
We can achieve the same behavior without nonlocal.
def outer():
context = {}
context['x'] = 1
def inner():
context['x'] = 2
print(context['x'])
inner()
print(context['x'])
Basic lexical vs. dynamic scoping...
MIT Scheme(lexical):
(define (definer)
(define x 1))
(define (printer)
(display x))
(define (letter)
(let ((x 2))
(printer)))
(definer)
(printer) ; error undefined variable
(letter) ; error undefined variable
Common Lisp(dynamic):
(defun definer ()
(defvar x 1))
(defun printer ()
(print x))
(defun letter ()
(let ((x 2))
(printer)))
(definer)
(printer) ; 1
(letter) ; 2
>>5 I guess it's something to get used to, and it does explain why in some lisp forums people have warned me that my local defines were actually global.
But, I mean, surely you can see calling these procedures without arguments and expecting to get different results depending on the context of the call kind of goes against Scheme's functional tendencies.
If you don't want to write in a functional style, Common Lisp is a much better choice. But that's not a deficiency of scheme (or Common Lisp), it's just a philosophical difference between the two languages.
With dynamic scoping the concept of global and local is abolished. Full control is given to the programmer. If one wants a different scope one has to explicitly create it. Once created, anything in that scope behaves as expected without magical implicit omissions or additions.
Scheme can be made to create similar non-functional side effects with (set!), but this is more complex and less useful than dynamic scoping.
>>7 You can also always use hash-tables or alists like in the python example. But different varieties of lisp are defined by different properties. Some have the everything in one name-space, some have different namespaces for functions and variables, and I think some add more after that. Some have fexprs, some don't. Some support tail recursion and some don't.
If you would prefer to stick to those dialects that allow dynamic scope, then by all means, do. But I don't see why the rest of us should take your preferences as anything more than that: your preferences. And we all have our preferences.
MIT Scheme:
(define s "I ENJOY TYRANNY")
(define (set-me-free)
(display s))
(let ((s "I AM FREE"))
(set-me-free))
Common Lisp:
(defvar s "I ENJOY TYRANNY")
(defun set-me-free ()
(print s))
(let ((s "I AM FREE"))
(set-me-free))
>>9 Not so fast.
(setf s "I ENJOY TYRANNY")
(defun set-me-free ()
(print s))
(let ((s "I AM FREE"))
(set-me-free))
Same result as second example assuming this is also Common Lisp.
>>11
https://rextester.com/BQX34910
https://rextester.com/XLJIR13883
You are correct. I was running the wrong script like a dummy.
http://www.lispworks.com/documentation/lw50/CLHS/Body/m_defpar.htm
defparameter and defvar establish name as a dynamic variable.
http://www.lispworks.com/documentation/lw50/CLHS/Body/m_setf_.htm
setf changes the value of place to be newvalue.
When you use setf you are specifically requesting that dynamic scoping not be used. Common Lisp gives us the choice, aka freedom from lexical tyranny.
>>13
Wow, how exotic and unique.
(define s (make-parameter "I ENJOY TYRANNY"))
(define (set-me-free)
(display (s)))
(parameterize ((s "I AM FREE"))
(set-me-free))
; => I AM FREE
This is an emulation of dynamic scoping not actual dynamic scoping. The variable has become a procedure.
>>15
So what? Just because Common Lisp uses the same syntax for lexical and dynamical/special variables, has not meant that all lisp have done this, nor that Scheme has to do it. It's not like dynamic scoping it inherintly more powerful, you could probably do something like that in C too (pinging FrozenVoid for a stupid and malformated example).
So what?
(define (create-me)
(define s (make-parameter "I AM BROKEN")))
(define (set-me-free)
(display (s)))
(create-me)
(parameterize ((s "I AM FREE"))
(set-me-free))
It's not like dynamic scoping it inherintly more powerful
Dynamic scoping is not arbitrarily limited, thus less tyrannical.
>>15
There's nothing emulated here, but there is some confusion of terminology. Parameters are first class objects, which makes them more powerful than plain old dynamically scoped variables. But they are not exactly variables. If you need variables, have a look at how fluids are built in Guile or make your own with dynamic-wind and some binding macro to hide the magic. It's done in a few minutes.
(It's not an emulation if it's just a real implementation. Here we're not building a meta-level where the new thing is possible, we're just doing it on the same level as everything else.)
MIT's fluid-let seems much more useful than guile's fluid system of explicit declarations. One still cannot define within a define though. There are most likely other limitations too because we are creating a dynamic environment within lexical environment.
muh freedom to shoot myself in the foot
>>16
https://github.com/FrozenVoid/C-techniques/blob/master/scope.c
Lack of indentation has progressed to actual intentional obfuscation.
>>22
I specifically indented the nested block scope example for pedants like you.
see raw text:
https://raw.githubusercontent.com/FrozenVoid/C-techniques/master/scope.c
>>24
What does that change?
>>25 Raw text preserves indentation as is, no browsers differences or css stylesheets will alter the appearance/indent/white-space/word-wrap/etc.
FrozenVoid is a shtick. He always posts unreadable C code.
>>27 thats not "unreadable", its code for public consumption.
I can write code with shorter variables and more macros.
Indentation also not used at all. Compare this with https://raw.githubusercontent.com/FrozenVoid/C-techniques/master/scope.c
#include "Util/void.h"
int g=4,l=50;
#define prscope(s) print(s,g,l)
void f(char*s){prscope(s);}
#define ex(s) ({prscope(s);})
void of(char*s){prscope(s);}
void f2(char* scope){int g=2000,l=6000;
void f3(char*s){prscope(s);};f3(scope);//2000,6000
atype fptr=of;fptr("\nGlobals again:");
ex("\nContext scope again:");}
int main(int argc,char**argv){
int g=5,l=100;
ex("\nContext scope:");
with(int g=1,l=2,prscope("\nLocal scope:"));
prscope("\nOuter scope:");
f("\nGlobal scope:");f2("\nDynamic scope:");
do{int g=-1,l=-400;prscope("\ndo loop context:");}while(0);
//inline block context {}
{int g=-44,l=-233;prscope("\nBlock scope:");
{int g=-20000,l=5055;prscope("\nNext layer of block scope:");
{int g=-201,l=654654;prscope("\nNesting of block scope:");}
prscope("\nNext layer of block scope returns:");}
prscope("\nBlock scope returns:");}
prscope("\nback to main context:");}
y
es
itm
ostd
efini
telyis
unreada
blebutyo
ualreadyk
newthatwha
tagreatshti
ckyoucreated
>>29 Perhaps, there is something like a mental block that blocks you from reading punctuation and instead relies on spatial cues like shape of text?
>>29,30 I see two major system of reading code:
A.By segmenting data by punctuation. This created a context for every block by parens/brackets/quote/etc used to delimit block boundaries.
A relies on simply counting current 'bracket level' +1/-1.
B.By segmenting data by spatical cues, such as indentation level(if all code fits on screen at once) from left side of content and its distance from nearby lines.
B system relies on monospace fonts, proper indentation and code fitting in one screen. It looks to me as fragile system where all conditions have to be met, so code will look "unreadable" if indentation is lost without becoming useless(Python code represents a code-decoding-form enforcing system B into compiler.)
>>31
Additionally, i see LISP code read through system A as expressions with deeply nested parens, which scales poorly vs system B. I assume all LISPers are forced to use system B or read parens levels instinctively without counting by using system B "visual line-length estimation" in monospace font like mentally comparing length of )))) vs ))). is that correct?
Is functional tyranny?
FrozenVoid giving us his detailed opinion, broken into as many posts as possible, about why code should be completely unreadable... In a thread about dynamic scoping. What a treat.
I'd like to see how System B readers interpret this:
https://i.postimg.cc/kGPVL8cF/Code-Example.png
>>28
I'd say try participating in the IOCCC, but your code never does anything, it's just unreadable, without any interesting side effects.
Functional programing is more like a consensual BDSM type of situation.
>>37
Have you notarized your consent forms(printed (in triplicate))?
>>31
Or C.: Recognizing and assuming conventional styles of programming. We are not computers that have to reparse a file again and again, instead we can remember patterns we are already familiar with. When someone uses a variable named "i", I'll assume it's a counter in C, until proven otherwise. Respecting style makes it easier for you and others to quickly gain an approximate understanding of what you are trying to do, defying usually looks like a infantile desire to be special.
>>39
Sounds robotic as fuck:
"Be conventional like every NPC, rely on memorized patterns, don't be special,approximate understanding, follow the crowd".(P.S. "We're totally not computers")
Master, I've made naughty side effects. I need a spanking!
Are you a programmer or a programmed code monkey?
>>40
Sounds like not wanting to create issues where it isn't necessary.
Hello?
>>44
Beep boop.
Boop beep
>>46
Syntax error.