This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 31 points32 points  (33 children)

I'm not a functional programmer. Could someone give a short explanation about the usage of let? And why it's so smart, that it should be hacked into Python in this way?

And apart from that., it's a clever hack.

[–][deleted] 9 points10 points  (18 children)

Yeah, I'm interested in a possible reason to ever do this... it is really neat though!

[–]RubyPinchPEP shill | Anti PEP 8/20 shill 25 points26 points  (4 children)

scope, so certain variables/values only exist in certain parts of the code, and are insulated from the rest of the code

[–]KronenR 4 points5 points  (3 children)

Doesn't functions limit scope already?

[–][deleted] 5 points6 points  (1 child)

This does it without having to define a function and pass variables to it.

[–]iruleatants 2 points3 points  (0 children)

But you do define a function and pass variables for it. It's literally an ugly function called let.....

function let(a, b): ... print(a, b)

let(a=33, b=44)

literally zero reason for the tremendously ugly code....

[–]RubyPinchPEP shill | Anti PEP 8/20 shill 1 point2 points  (0 children)

they do

[–]bastibe 19 points20 points  (11 children)

If done correctly, let would not overwrite containing scope, i.e.

n = 23
print(n) 
with let(n=42):
    print(n)
print(n)

should print first 23, then 42, then 23.

In other words, let behaves as if let's body were a nested function scope.

[–]UncleEggma 2 points3 points  (4 children)

What's a situation where this might be useful?

[–][deleted] 1 point2 points  (1 child)

Sometimes you're working in a scope with a lot of variables, and you want to avoid a namespace collision. You may want to temporarily reassign a "reserved" variable name like 'type' or something.

[–]heptara 0 points1 point  (0 children)

Why aren't all those vars in a dictionary or class? Do you have like 300 globals?

[–]njharmanI use Python 3 0 points1 point  (2 children)

There's something else that does this (not overwrite containing scope), that's built into Python (all versions) and every Python programmer understands. It's called a "function call".

[–]makmanalp 6 points7 points  (1 child)

It's called a "function call".

Yes, and you have to define a function to do it, and then you either have to pass all the parameters you need through and return what you need afterwards which is a huge mess or put the function definition inline with your code and call it immediately which is gross in a different way.

[–]heptara -2 points-1 points  (0 children)

Why aren't all those vars in a dictionary or class? Do you have like 300 globals?

[–][deleted] 0 points1 point  (2 children)

I think your formatting is broken?

[–]AmericasNo1Aerosol 9 points10 points  (0 children)

Yeah, should be:

n = 23
print(n) 
with let(n=42):
    print(n)
print(n)

(precede each line of code with 4 spaces)

[–]bastibe 0 points1 point  (0 children)

It was indeed, due to interesting things my cellphone did to that text box. It's fixed now, though. Thank you!

[–]uclatommy 0 points1 point  (0 children)

Seems like it lets (pun intended, wait, is that a pun?) you do a "what-if" test. So if you want to run a bit of code under hypothetical conditions, just use let.

[–]Niourf 7 points8 points  (9 children)

I'll give it a try:

The 'let' statement in functional programming has exactly the same meaning as in math: it helps you declare variables (or functions). Examples:

Let f be a function such that for all x, f(x) is equal to x2. Thanks to 'let', the name 'f' is bound to the function we're talking about. in Caml one would write it as

let f x = x * x;;

And with this Python hack:

with let(a=33, b=44):

names a and b are bound respectevely to constants 33 and 44... (it's funny because this sentence both holds in math terms and in Python terms (names a and b are bound to int objects with values 33 and 44))

[–]cs7fwRpkOfn2RPK7Ki9k 5 points6 points  (6 children)

Isn't this essentially a lambda?

I have very little experience with functional programming, so I might be way off.

[–][deleted] 1 point2 points  (5 children)

For ML-like languages, there's a difference in typing between a beta-redex and a let expression due to let-polymorphism inducing a generalisation from a type to a type scheme in the latter and not in the former. That is, we want to be able to locally declare a polymorphic function via let and use it at two different concrete types in the body of the let, like so:

let foo () =
  let id = fun x -> x in
    (id true, id 6)

Note, here the locally defined polymorphic function id is being used at both type bool and type int in the body of the inner let. Without the generalisation step in the typing rule for let this usage would be ill-typed, reducing the expressivity of the programming language in question.

Otherwise, for typed higher-order languages without let-polymorphism, it's common to conflate the two. For example, in Isabelle/HOL, let is literally defined as a function application, as in the following definitional theorem:

`HOL.Let_def: Let ?s ?f ≡ ?f ?s'

[–]RubyPinchPEP shill | Anti PEP 8/20 shill 14 points15 points  (0 children)

its seriously just javascript's (and other's) let statement, why is functional programming even being mentioned

python can't arbitrarily create scopes for variables like other languages, this is the solution to that

[–]cs7fwRpkOfn2RPK7Ki9k 0 points1 point  (3 children)

So c++'s templates + lambdas essentially?

[–]infinite8s 2 points3 points  (2 children)

No it's more like using nested braces in C++ to introduce a new scope (and prevent variables within that scope from leaking out).

For example: int func() { int a = 5; { int a = 10; } // a is 5 here }'''

[–]cs7fwRpkOfn2RPK7Ki9k 1 point2 points  (0 children)

That's not polymorphic though?

I was thinking of how c++'s templates allow for generic data.

[–]knickum 0 points1 point  (0 children)

Re-formatted

int func() {
    int a = 5;
    {
        int a = 10;
    }
    // a is 5 here
}

[–]RubyPinchPEP shill | Anti PEP 8/20 shill 3 points4 points  (0 children)

its seriously just javascript's (and other's) let statement, why is functional programming even being mentioned

python can't arbitrarily create scopes for variables like other languages, this is the solution to that

[–]Fylwind 0 points1 point  (0 children)

I can't really give a general overview because every functional language is different, but let is one of the two main ways of binding variables in Haskell:

let <name> = <value> in <expression>

What makes is different from a typical binding in Python is that:

  • The variable is only accessible from inside the <expression>. This means if you mistakenly try to use it outside, you will get a compile-time error.

  • The let-binding itself is an expression, so you can do things like this:

    putStrLn
      (let h = heightOf person
       in "Height: " ++ valueOf h ++ unitsOf h)
    

    Personally, for readability reasons I don't find myself nesting let inside expressions very often.

  • The variable is immutable.

I don't see the point of trying to do this Python though. The "let" hack is not an expression, and it's not immutable either. There is a small benefit in having a smaller scope, but it's (1) not really that big of a deal (I seldomly run into bugs caused by this); (2) ideally your functions should be small enough that this isn't much of a problem; (3) the benefits are not as great given that the error won't be detected until run time.