Why Use an Extra Let Statement Here

Why use an extra let statement here?

The if-let construction is sort of superfluous in a simple case like this, but in a more complicated piece of code it can be useful. You can use it in a lot of the same ways you'd use an assignment in a conditional in (Obj)C (remember if (self = [super init])).

For example, if the optional being tested is a computed property:

var optionalName: String? {
get {
if checkTouchID() {
return "John Appleseed"
} else {
return nil
}
}
}
var greeting = "Hello!"
if optionalName {
greeting = "Hello, \(optionalName)"
}

Paste that into a playground, along with a stub implementation of checkTouchID() that returns true, and you'll immediately see in the results area that the optionalName getter is executing twice. If you use an if-let construction instead, you'll only execute the getter once.

This also true — and perhaps more commonly useful — if you have a series of chained optional calls, as in the if let johnsStreet = john.residence?.address?.street example from the docs. You don't want to rewrite the whole chain in the body of the if statement, much less recompute it.

In Haskell, when do we use in with let?

Short answer: Use let without in in the body of a do-block, and in the part after the | in a list comprehension. Anywhere else, use let ... in ....


The keyword let is used in three ways in Haskell.

  1. The first form is a let-expression.

    let variable = expression in expression

    This can be used wherever an expression is allowed, e.g.

    > (let x = 2 in x*2) + 3
    7
  2. The second is a let-statement. This form is only used inside of do-notation, and does not use in.

    do statements
    let variable = expression
    statements
  3. The third is similar to number 2 and is used inside of list comprehensions. Again, no in.

    > [(x, y) | x <- [1..3], let y = 2*x]
    [(1,2),(2,4),(3,6)]

    This form binds a variable which is in scope in subsequent generators and in the expression before the |.


The reason for your confusion here is that expressions (of the correct type) can be used as statements within a do-block, and let .. in .. is just an expression.

Because of the indentation rules of haskell, a line indented further than the previous one means it's a continuation of the previous line, so this

do let x = 42 in
foo

gets parsed as

do (let x = 42 in foo)

Without indentation, you get a parse error:

do (let x = 42 in)
foo

In conclusion, never use in in a list comprehension or a do-block. It is unneccesary and confusing, as those constructs already have their own form of let.

Statements not executing in order? (defvar within a let statement)

See the documentation for defvar in the Hyperspec:

If a defvar or defparameter form appears as a top level form, the compiler must recognize that the name has been proclaimed special.

This implies (and it seems to be the case for SBCL) that if a defvar appears as a non-top-level form, then the compiler need not recognize that the name has been declared. So how come your defvars are not being compiled as top level forms? See section 3.2.3.1, Processing of Top Level Forms (point 6) for the answer: the let surrounding your code causes it to be compiled as non-top-level forms.

So you need to defvar your variables at top level, and then assign them later on with setf inside the let.


Like this. It's also usually simpler to use with-open-file rather than open and close.

(defvar var1)
(defvar arr1)

(with-open-file (input "input.lisp" :direction :input)
(setf var1 (read input))
(setf arr1 (make-array var1 :initial-contents (read input))))

(print var1)
(print arr1)

The reason that you are having this trouble is that you are placing your code at top level in the file. This is a slightly unusual thing to do: the normal Lisp coding style is to put most of your code in function definitions, and then to call those functions when you need to run them.

For example, this would be a more typical way to write this kind of code, with the initialization code in its own function.

(defvar *var1* nil "Documentation for var1.")
(defvar *arr1* nil "Documentation for arr1.")

(defun init-from-file (file)
"Read *var1* and *arr1* from file."
(with-open-file (input file :direction :input)
(setf *var1* (read input))
(setf *arr1* (make-array *var1* :initial-contents (read input)))))

(when (null *var1*) (init-from-file "input.lisp"))

How pattern matching in Rust works with `let` statement

he compiler suggests that let &x = &foo moves the string hello, which I'm aware of and don't see where the problem is

The problem is that you've given the compiler an immutable reference to a variable (&foo) and then asked it to move away the underlying data. Which is not an operation that is permitted by immutable references.

To make this more explicit, extract the moving-out part into another function:

fn pattern_matching_1_helper(r: &String) {
let &x = r;
println!("{}", x);
}

fn pattern_matching_1() {
let foo = String::from("hello");
pattern_matching_1_helper(&foo);
}

I hope it's obvious that pattern_matching_1_helper cannot compile on its own. But the combined version in your code is really no different.

pattern_matching_2 compiles because i32 is Copy, so the compiler doesn't need to move.

What is the difference between let and var?

Scoping rules

The main difference is scoping rules. Variables declared by var keyword are scoped to the immediate function body (hence the function scope) while let variables are scoped to the immediate enclosing block denoted by { } (hence the block scope).

function run() {
var foo = "Foo";
let bar = "Bar";

console.log(foo, bar); // Foo Bar

{
var moo = "Mooo"
let baz = "Bazz";
console.log(moo, baz); // Mooo Bazz
}

console.log(moo); // Mooo
console.log(baz); // ReferenceError
}

run();

Why was the name 'let' chosen for block-scoped variable declarations in JavaScript?

Let is a mathematical statement that was adopted by early programming languages like Scheme and Basic. Variables are considered low level entities not suitable for higher levels of abstraction, thus the desire of many language designers to introduce similar but more powerful concepts like in Clojure, F#, Scala, where let might mean a value, or a variable that can be assigned, but not changed, which in turn lets the compiler catch more programming errors and optimize code better.

JavaScript has had var from the beginning, so they just needed another keyword, and just borrowed from dozens of other languages that use let already as a traditional keyword as close to var as possible, although in JavaScript let creates block scope local variable instead.

JavaScript: Understanding let scope inside for loop

General Explanation

When you use let in the for loop construct like you show, there is a new variable i created for each invocation of the loop that is scoped just to the block of the loop (not accessible outside the loop).

The first iteration of the loop gets its value from the for loop initializer (i = 1 in your example). The other new i variables that are created each loop iteration get their value from the i for the previous invocation of the loop, not from the i = 1 which is why they aren't all initialized to 1.

So, each time through the loop there is a new variable i that is separate from all the other ones and each new one is initialized with the value of the previous one and then processed by the i++ in the for loop declaration.

For your ES6 code of this:

for(let i = 1; i <= 5; i++) {   setTimeout(function(){       console.log(i);   },100);} 

let...in' expression in Scala

EDIT:

You learn something new every day, and this has been answered before.

object ForwardPipeContainer {
implicit class ForwardPipe[A](val value: A) extends AnyVal {
def |>[B](f: A => B): B = f(value)
}
}

import ForwardPipeContainer._

def squareTheSum(a: Int, b: Int): Int = { a + b } |> { sum => sum * sum }

But I'd say that is not nearly as easy to read, and is not as flexible (it gets awkward with nested lets).


You can nest val and def in a def. There's no special syntax; you don't need a let.

def squareTheSum(a: Int, b: Int): Int = {
val sum = a + b
sum * sum
}

I don't see the readability being any different here at all. But if you want to only create the variable within the expression, you can still do that with curly braces like this:

val a = 2                                       //> a  : Int = 2
val b = 3 //> b : Int = 3
val squareSum = { val sum = a + b; sum * sum } //> squareSum : Int = 25

There is no significant difference here between a semicolon and the word "in" (or you could move the expression to the next line, and pretend that "in" is implied if it makes it more OCaml-like :D).

val squareSum = {
val sum = a + b // in
sum * sum
}

Another, more technical, take on this: Clojure's 'let' equivalent in Scala. I think the resulting structures are pretty obtuse compared to the multi-statement form.

Scope of functions and variables within a function and/or let statement for lisp

Why it is difficult to discuss the effects you see:

You are doing things which are undefined in Common Lisp: setting undeclared variables in test-scope1: myvar. It's from then on unclear how the following code behaves.

Undeclared Variables

It is undefined what effect it has when an undeclared variable foo is set. Implementations allow it. Some will warn. SBCL:

* (setf foo 10)
; in: SETF FOO
; (SETF FOO 10)
; ==>
; (SETQ FOO 10)
;
; caught WARNING:
; undefined variable: FOO
;
; compilation unit finished
; Undefined variable:
; FOO
; caught 1 WARNING condition

Global variables are defined with DEFPARAMETER and DEFVAR. Local variables are defined by LET, LET* and by functions parameters. Since DEFPARAMETER and DEFVAR define global special (using dynamic binding) variables, it is common to write them as *some-variable* - note the * around it, which are part of the symbol name and not special syntax. It's a convention for special variables.

Nested DEFUNs

Nested DEFUNs are not used in Common Lisp. DEFUN is a top-level form, which sets a global function. To define local functions use FLET and LABELS. You can nest DEFUN forms, but it is bad style and you won't find it used in actual Lisp code. Don't nest DEFUN forms. Note: this is different from Scheme, where one can nest DEFINE forms. Since nested DEFUNs are not used, it makes little sense to discuss the effects. Convert the examples to use local functions defined by FLET or LABELS.

  • When I do a defun inside another defun, even in a let block, why does that function become accessible globally?

Because DEFUN defines global functions. That's its purpose.

You need to rewrite your examples to make it possible to discuss the effects:

  • declare all variables

  • don't use nested DEFUNs

We could try to understand the code you have in your current examples, but much depends on the implementation and the sequence of actions. We are either not in the realm of portable Common Lisp or doing stuff (nested DEFUNs), which has no practical use in Common Lisp.



Related Topics



Leave a reply



Submit