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.
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
7The second is a let-statement. This form is only used inside of do-notation, and does not use
in
.do statements
let variable = expression
statementsThe 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
ordefparameter
form appears as a top level form, the compiler must recognize that the name has been proclaimedspecial
.
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 defvar
s 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 DEFUN
s 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
DEFUN
s
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
Error "No Such Module" When Installed Framework with Pod in Swift 3
Nsbutton Background Transparent After Getting Focus
How to Create a Hotspot Network in iOS App Using Swift
Swift:Pause and Resume Nstimer
Infer Closure Return Type from Closure Body When Working with Generics
How to Synchronize Coredata with Webservices in Swift
JSONserialization.JSONobject Performance in Swift
Swiftui Navigation: How to Switch Detail View to a Different Item
Format Println Output in a Table
How to Cancel Firebase Setvalue While Pending for Completion (When Offline)
Adding Index List and Section Headers to Translated Tableview
Using Uilexicon to Implement Autocorrect in iOS 8 Keyboard Extension
How to Detect Text View Begin Editing and End Editing in Swift 3
Xcode Build Perfect Failure -- Copenssl Not Found
Pattern Variable Binding Cannot Appear in an Expression
How to Convert an Anykeypath to a Writablekeypath
Swiftui View and Uihostingcontroller in Uiscrollview Breaks Scrolling
Realmswift Initialize List:Cannot Specialize a Non-Generic Definition