Dynamic Scoping Analysis and Variable Inference in Functional Programming
This document explores the complexities of dynamic scoping and variable inference within functional programming paradigms. It delves into issues related to how variables are scoped, the implications of dynamic versus lexical scopes, and provides insight into variable resolution mechanics. By analyzing scenarios involving tracebacks, unused variables, and conditionals, it illustrates practical examples that highlight common pitfalls and solutions in variable handling. This work serves as a resource for programmers seeking to enhance their understanding of functional programming principles and optimize code reliability.
Dynamic Scoping Analysis and Variable Inference in Functional Programming
E N D
Presentation Transcript
let x initExpr in collect(j|...)->any(true) select(i|...) source body source body self.f j.e x.a.d let y in initExpr if y.b>i.c+x.a cond then else x.a>i.c let z self.g>3 initExpr in i.c-2 z+i.c
let x initExpr in collect(j|...)->any(true) select(i|...) source body source body self.f j.e x.a.d let y in initExpr if y.b>i.c+x.a cond then else x.a>i.c let z self.g>3 initExpr in i.c-2 z+i.c
let y in initExpr self let z initExpr in y.h.k y+z traceback on y.h; unused for y.h; unused for y.h.k; unused for z in y+z; unused for y+z in y+z (=false) traceback on y (after reverse-traversal across y.h); unused for y; unused for y.h (cached=false) --> on to initExpr for let-variable y: traceback(no-unused) on self
let x • traceback for i.b, unused for i.b-->i.b.c-->i.b.c+x.g--> z in z, unused for let z, [[i.a>2]] with unknown i • traceback for i; resolves [[i.a>2]], unused for i-->i.b (cached) • traceback for x.a.d leaving select body (let y) scope; unused for x.a.d--> select-->let x (false) • traceback for x.a; unused for x.a-->x.a.d (cached) • traceback for x; unused for x-->x.a (cached) • traceback(cache: unused(self.f)=false) for self.f • traceback for self; unused for self-->self.f (cached: false) initExpr in self.f select(i|...) source body x.a.d let y in initExpr if y.b>i.c+x.a cond then else i.a>2 let z self.g>3 initExpr in i.b.c + x.g z
traceback for x.z in d(...) infers x, branch: • traces back to self.d(x,y) and infers x, traces back to self.b(x, y) and infers x --> [[x.z>y.z]] for unknown y@0 • traces back to self.d(y,x) and infers y, traces back to self.c(x, y) and infers y@1; does not trigger [[x.z>y.z]] because dynamic scope y@0<>y@1. • Problem: actually, the dynamic scopes would have been the same a(x:T, y:T):Integer body: if x.z > y.z then self.b(x, y) + self.c(x, y) else ... endif b(x:T, y:T):Integer body: self.d(x, y) c(x:T, y:T):Integer body: self.d(y, x) d(x:T, y:T):Integer body: x.z + y.z
let y initExpr in self select(i|...) source body x.a.d let z initExpr in y.h.k z+i traceback on y.h; unused for y.h; unused for y.h.k; unused for z in z+i; unused for z+i in z+i (=false) traceback on y (after reverse-traversal across y.h); unused for y; unused for y.h (cached=false) --> on to initExpr for let-variable y: traceback on self (insert into cache: unused(self)=false); unused for self (cached: false)
iterate(result=self; i|...) • traceback for result, entering result value for current dynamic scope #n; unused for result--> result.c--> [[self.a.d]] with unknown self--> iterate (false) • branch: • traceback for self, infers one of potentially several values for self; unused for self--> iterate (false) • traceback for result.c, entering new dynamic scope for result.c (n++); unused for result.c but in different dynamic scope than the one cached-->[[self.a.d]] with yet unknown self (self values inferred on the other branch don't count in this branch) source body self.a.d result.c If a value is inferred for self, this triggers the [[self.a.d]] callback