Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

Let/lambda equivalence

Name: Anonymous 2012-08-13 20:54

Most call-by-value languages with anonymous functions have let/lambda equivalence: declarations are exactly the same as function parameters/arguments.
((lambda (i j) (* i j)) 3 4)
(let ((i 3) (j 4)) (* i j))


((INT i, j)INT: i * j)(3, 4)
(INT i = 3, j = 4; i * j)


(fn (i, j) => i * j)(3, 4)
let val (i, j) = (3, 4) in i * j end


A related rule is that any expression can be wrapped in a lambda without changing its meaning (besides grouping the expression). Notice how it is the expressions within the lambda bodies that create the scope in which the variables are bound and not the lambdas themselves.
((lambda () (let ((i 3) (j 4)) (* i j))))
INT: (INT i = 3, j = 4; i * j)
(fn () => let val (i, j) = (3, 4) in i * j end)()


One popular language does not follow these rules. Can you guess what it is? It's a language where certain constructs need to be wrapped in functions which are called immediately. It's supposedly ``Scheme-inspired'' but it's statement-based and uses a return keyword. The upcoming version will add a new type of function and variable that does follow these rules, at the expense of having two sets of rules and bloating the language beyond C++.
Give up? It's JavaScript.

Name: Anonymous 2012-08-13 22:44

u told him bro

Name: Anonymous 2012-08-13 23:01

alright what's the lambda equivalent of let*?

Name: Anonymous 2012-08-13 23:26

>>3
It's nested lambdas, or currying if the language has a syntax for it.
(let* ((a 1) (b (+ a 2))) (+ b 3))
((lambda (a) ((lambda (b) (+ b 3)) (+ a 2))) 1)

Name: Anonymous 2012-08-14 1:11

This is the best thread on the entire net right now.

Name: Anonymous 2012-08-14 7:37

>>1
I thought you meant FIOC.

Name: Anonymous 2012-09-17 21:06

This is a relevant thread, therefore I must bump it.

Name: Anonymous 2012-09-17 21:10

>>1
I thought for sure it was clojure

Name: Anonymous 2012-09-17 21:15


(define (identity x) x)
(define indentity (λ (x) x))

;;does this work in Scheme?
(define defun (λ (name args func)
                (define (name args) func)))

Name: Anonymous 2012-09-17 21:59

> (function(f) { f(f); })(function(f) { f(f); });
RangeError: Maximum call stack size exceeded


lol!

Name: Anonymous 2012-09-18 3:00

>>9
I don't have a REPL here, so does it?

>>10
How exactly is that funny? What are you, 12?

Name: Anonymous 2012-09-18 4:39

>>11
I'm 12 nice to meet you

Name: Anonymous 2012-09-18 11:38

>>11
It's funny because a language that's supposedly based on Scheme doesn't optimize tail calls.

Name: Anonymous 2012-09-18 12:32

>>13
so if the language supports tail calls, that code should be an infinite loop?

Name: Anonymous 2012-09-18 16:59

>>10,13
Tail call optimization would break the caller property.

function stacktrace() {
  console.log("-- START OF STACKTRACE --");
  for(var f = arguments.callee.caller; f instanceof Function; f = f.caller)
    console.log(f);
  console.log("--  END OF STACKTRACE  --");
}

Name: Anonymous 2012-09-18 17:00

>>13
js is the closest to scheme of any scripting language by a longshot

Name: Anonymous 2012-09-18 17:32

>>16
lel

Name: Anonymous 2012-09-18 17:35

>>13
So taking inspiration requires people to copy every detail?

Name: Anonymous 2012-09-18 20:39

>>1
I seem to recall reading something stating let being short for lambda-something.

One thing I have stuck by though is having been introduced to let in terms of lambdas, and equivalence is fairly important to me. JS is still pretty good though, if you keep in mind the edges are quite jagged.

>>6
FIOC doesn't even have lambda-lambda equivalence.

>>15
I hear people use that sorry excuse all the time. It's nonsense though. With a self-recursive operation (especially one that equates to iteration) there is no reason to add yet more calls onto the stack trace. You don't record every pass through a loop construct after all.

For mutually recursive functions, I just think of it as factoring the case analysis bodies out of the main function. If your language has letrec then it's made clear what system of functions you're in anyway.

>>18
No one said that, but it is funny. Yet it's more sad than funny. The more powerful things are eschewed (ever write a state machine without recursion—bleh) to afford the opportunity to include ever more garbage I don't want to read when the program crashes.

Name: Anonymous 2012-09-18 21:33

>>19
Stack traces are just a trivial example of what can be done with the caller property. You can pull functions from anywhere in the call stack and call them. You can modify the arguments object in any of the functions in the call stack. You can check the call stack for functions named in camelCase. The possibilities are endless.

Name: Anonymous 2012-09-18 21:56

>>20
Can you think of something useful which is difficult to achieve by other means?

Name: Anonymous 2012-09-18 22:03

>>20
Treating scoped function arguments as global shared data
Why would you do that?

Name: Anonymous 2012-09-18 22:18

>>22
Why not?

Name: Anonymous 2012-09-18 23:16

>>23
dynamic scoping is shit. If you want to understand why, all you have to do is try to program using it. Then, then you'll see why it isn't that great of an idea for a function to behave differently based upon the environment it was called from, something that changes with every invocation and certainly can't be predicted at the time when you are writing the definition of the function.

Name: Anonymous 2012-09-18 23:47

>>24
That's not really dynamic scoping... it's... something hideous and pointless. There are legitimate uses for dynamic scoping, which I've found out the hard way.

Name: Anonymous 2012-09-18 23:47

>>24
That sounds exactly like programming with state. This is why programs should be as purely functional a possible.

Name: Anonymous 2012-09-19 0:01

>>25
I think we are using the term differently. In the one I was referring to, it is where the names of variables are resolved to values by looking down the functional call stack.

http://en.wikipedia.org/wiki/Scope_%28computer_science%29#Dynamic_scoping

I'd be surprised if anyone found a good use for dynamic scoping, although I'd be interested in hearing your use for it,

Name: Anonymous 2012-09-19 0:22

>>26
Dynamic scoping is the same as global variables except each variable is a stack.

Name: Anonymous 2012-09-19 0:49

>>28
That'd be a nightmare for me. I can barely imagine a non-trivial system that's dynamically scoped. I'd have to make use of funky variable names to help manage the state of the system.

Name: Anonymous 2012-09-19 0:52

>>27
Oh, that's what I was talking about, but you don't need to give the user access to the call chain to do that. I thought you were equating it to what the other fellow was talking about.

On the subject of dynamic scope and recursion, I would love to see a problem that would be best handled by dynamically scoped variables that change value within the recursive call group. I don't believe such a case exists, so I would find it most fascinating.

My use is simple. A library I use maintains some state in a global (for a passable reason), but I need to change that state depending on the task my code is working on. Since I use coroutines, this saves me from having to set it at every point the function is reentered, which would be after every potentially blocking call—and that wouldn't even work, many of those are 3rd party library calls which would do work after blocking, keeping the incorrect value from some other function until they eventually returned to my code where I could finally restore the value.

So in that you need globals that provide some sort of context for execution, dynamic scope has the potential to be genuinely useful.

I recall being convinced of a few other cases. It's usually used for things like redirecting a logger for a given chain of calls. Whatever the case, it probably involves changing the environment for a particular task to execute in.

Anyway, I'll finish off with a horrifying factoid: loops in bash dynamically scope all variables within the loop body. No, you can't turn it off.

Name: Anonymous 2012-09-19 1:14

>>30

Dynamic scoping can be useful if it is manageable. If you could turn it on for only a few variables, and treat them with the same discretion used with global variables, I could see it working. The trouble is that it requires coordination between the function that references the variable and some parent function that happened to initialize the variable. This becomes very difficult to keep track of when it is used more and more. It's even worse if you are allowed to modify the dynamically scoped variables. You might depend on the global variable being changed, but instead some local variable in the middle of the call stack got it, and then was destroyed when it went of scope. Trying to do anything in a language where things like that can happen unpredictably is just terrible. It could be ok if you have to explicitly declare variables to have dynamic scope.

You can always get the same power as dynamic scope by explicitly passing the variable down to the child functions through the parameters. It is verbose, but it accomplishes getting the values to where they are needed and you have the flexibility of renaming parameters or changing them as they are passed down. If you have a lot of values to pass, you can wrap them in an object and pass around with a single reference.

Name: Anonymous 2012-09-19 1:15

>>30
loops in bash dynamically scope all variables within the loop body. No, you can't turn it off.
Terrible!

Name: Anonymous 2012-09-19 1:33

>>31
If you could turn it on for only a few variables, and treat them with the same discretion used with global variables, I could see it working.
That's the idea, in part.

The trouble is that it requires coordination between the function that references the variable and some parent function that happened to initialize the variable.
Nah, you're already using a dynlang. All you need is some context providing information on which variables are dynamically scoped. (You don't even need that, but it makes proper global lookups faster if you know which ones not to chase.)

You might depend on the global variable being changed, but instead some local variable in the middle of the call stack got it, and then was destroyed when it went of scope.
Not really a problem in practice. You normally only scope certain kinds of global variables. If a function changes a variable in dynamic scope, it is the one asserting that all subsequent calls are to be made in that context. Don't worry about what the callee wants, it's what the caller wants (after all, if the callee wasn't asking for external information, it would be using a global variable in the first place.)

You can always get the same power as dynamic scope by explicitly passing the variable down to the child functions through the parameters.
That's debatable on semantics. You'd have to pass down the entire global scope at all times to make it general. And addressing a "globals" (you no longer have true globals, since you can only access them via local reference) requires two dereferences, since this dynamic aspect only works with a collection of references, not the collection of values. I think its entirely unfeasible.

Dynamic scope is not a problem when it comes to voluntary use. Just don't use it when you don't need it and it won't be an issue. And never write anything complicated in bash.

Name: >>33 2012-09-19 1:35

*would not be using a global variable in the first place.

Name: Anonymous 2012-09-19 1:52

>>33

Dynamic scope is not a problem when it comes to voluntary use. Just don't use it when you don't need it and it won't be an issue.

true that.

And never write anything complicated in bash.

yes, that too. I learned my lesson with forced dynamic scoping using glorious postscript. I tried to implement an object system and was able to use dynamic scoping to emulate this. But things became terrible quickly. I'll need to find that code again.

Don't change these.
Name: Email:
Entire Thread Thread List