I've found block scope {and } in JavaSciprt after ES6 is useful in development, and frequently use for testing small code blocks including the same variable names in different versions side by side.
How do you do in Haskell? What's the best prctice?
If you have some code like this:
foo x y = do
print x
print y
And you want to temporarily test changing the value of x then you can just write:
foo x y = let x = 2 in do
print x
print y
This let syntax creates a new scope and "overwrites" (shadows) any variables with the same name that were previously bound. You can use this let almost everywhere, e.g.:
foo x y = do
let x = 2 in print x
print y
Or even:
foo x y = do
print (let x = 2 in x)
print y
It is really flexible.
There's a few choices, depending on what context you're looking for. I think the thing most likely to be useful to you is that each binding can be associated with a where block, and the variables in each block are independent. So, for example:
foo = component1 * component2 where
component1 = x + y where
x = 32
y = sqrt (magnitude velocity)
component2 = x + y where
x = magnitude acceleration
y = 5.5
In each case, the x and y are in scope only for the component that's currently being defined.
One place that doesn't always work well is in do blocks. There's two reasons for this: first, the associated where block's scope doesn't include any of the variables bound by statements in the do block, and second, because sometimes the thing you want is differing scopes for differing parts of the do block. For those cases, let/in works better. For example:
foo = do
let x = print "hi"
y = putStrLn "hi"
in do
x
y
-- x and y are no longer in scope here
v <- readLn :: IO Int
let x = print [v] -- v is in scope, unlike a where block
y = print v
in do
x
y
Again, in each case, the x and y are in scope for the body of the nested do block, but not in scope in the outer do block. It is also possible to add something to the outer do block's scope, though of course the syntax has to be different (or how would the compiler know which one you wanted?). The difference is that you leave off the in, so:
foo = do
v <- readLn :: IO Int
let w = v + v
print w
Related
In Haskell, I am trying to write something like
function x = do
y <- get x
put y
let z = Map.lookup y
case y of
Nothing -> Nothing
Just y -> do... (something)
I want to replace the "let..case of" block with something like a "where..case of" block or "where" block if possible. How can I do so?
You can define a function with pattern matching in a where block. (I don't know, if it is a better solution because you didn't explain very well what does the function do, but it is possible):
function x = do
y <- get x
put y
let z = Map.lookup y
fn y
where fn Nothing = Nothing
fn (Just n) = do... (something)
Also, note that you can use fmap:
function x = do
y <- get x
put y
let z = Map.lookup y
fmap fn y
where fn n = do... (something)
First of all, I want to say that I'm very very inexperienced with Haskell, and I know that I have done something (or multiple things) terribly wrong, been struggling for hours but I can't seem to find it.
power :: Int -> Int -> Int
power x y | y == 0 = 1
| x == 0 = 0
list = replicate y x
foldr (*) x list
main = print $ power 3 5
Error most of the time is either x and y not being passed to the replicate function or that foldr is a naked function, I understand what they both mean but have no idea on how I can pass the variables or come up with a solution.
You here created four functions: power, list, foldr and main. But you use variables x and y in the definition of the list function.
You can work with a where clause to specify subexpressions, for example:
power :: Int -> Int -> Int
power x y | y == 0 = 1
| x == 0 = 0
| otherwise = foldr (*) 1 list
where list = replicate y x
or perhaps more elegant with pattern matching:
power :: Int -> Int -> Int
power 0 _ = 0
power x y = foldr (*) 1 (replicate y x)
main = print $ power 3 5
Here we can also eliminate the case for x0, since our foldr starts working with 1, not x.
This algorithm is however not very efficient, since it is linear in the value of y. By checking recursively if the exponent is even or odd, you can make it faster. I leave this as an exercise.
You were very close! The main things that need to be fixed are:
When writing a definition with guards, the “fallback” case needs to be a guard as well, conventionally written with otherwise.
Recall that a definition without guards looks like this, with one left side (a name and parameter patterns/names) and one right side (an expression):
name patterns = expression
With guard conditions, there is one right-hand side for each guard:
name patterns | condition1 = expression1
| condition2 = expression2
…
| otherwise = expressionn
otherwise is really just an alias for True, that is, such a guard always matches. The only thing special about otherwise is that the compiler uses it as a hint when analysing whether a pattern match covers all possible cases.
In order to define a variable list, local to the definition of power, using the parameters x and y, you need to use either a let…in… expression, that is, let block in expression, or a where clause, equation where block. A block is a series of items (in this case, local definitions) which must all be written starting at the same column of indentation, or be delimited by explicit curly braces {…} and semicolons ;.
Using let…in… follows the structure of your original code pretty closely. I will adjust the indentation style to avoid needing to align anything, by putting a newline and a constant amount of indentation instead.
power :: Int -> Int -> Int
power x y
| y == 0 = 1
| x == 0 = 0
| otherwise = let
list = replicate y x
in foldr (*) x list
main :: IO ()
main = print $ power 3 5
Attaching a where clause to an equation is slightly more common than using a let…in… expression on the right side of an equation.
power :: Int -> Int -> Int
power x y
| y == 0 = 1
| x == 0 = 0
| otherwise = foldr (*) x list
where
list = replicate y x
main :: IO ()
main = print $ power 3 5
Note that in this case, there is a slight difference: the variable list is visible in all of the right-hand sides, although we only use it in one of them. With let list = … in e, list is only defined within e. In general, it’s helpful for readability to keep the scope of a variable as small as possible, although you can certainly go overboard:
a = …
where
b = …
where
c = …
where
d = …
-- If you see this much nesting, rethink!
If you run into issues with alignment and indentation, you can always use explicit delimiters instead. The code I wrote is equivalent to the following.
power :: Int -> Int -> Int; -- Begin ‘power’ signature.
power x y
| y == 0 = 1
| x == 0 = 0
| otherwise = let { -- Begin ‘let’ block.
list = replicate y x; -- End ‘list’ equation.
} in foldr (*) x list; -- End ‘let’ block, then end ‘power’ equation.
main :: IO (); -- Begin ‘main’ signature.
main = print $ power 3 5; -- End ‘main’ equation.
Or similarly with where { … }.
count_instances :: (Int)->([Int])->Int
count_instances x [] = 0
count_instances x (t:ts)
| x==t = 1+(count_instances x ts)
| otherwise = count_instances x ts
i just want to know whats so good about using guards in this Question ?
A guard can be a way to write only one half of an if-then-else expression; you can omit the else and have a partial function.
-- Leave the function undefined for x /= y
foo x y | x == y = ...
You can do the same with a case statement, but it's more verbose
foo x y = case x == y of
True -> ...
It's also easier to list several unrelated conditions as a set of alternatives than it is with a nested if-then-else or case expressions.
foo x y | p1 x y = ...
foo x y | p2 x y = ...
foo x y | p3 x y = ...
foo x y = ...
vs
foo x y = if p1 x y then ...
else (if p2 x y then ...
else (if p3 x y then ... else ...))
Patterns with guards are probably the most concise way to write code that otherwise would require nested case/if expressions.
Not the least advantage is that a where clause applies to all the guards right hand sides. This is why your example could be even more concise:
count_instances :: (Int)->([Int])->Int
count_instances x [] = 0
count_instances x (t:ts)
| x==t = 1+rest
| otherwise = rest
where rest = count_instances x ts
A guard is haskell's most general conditional statement, like if/then/else in other languages.
Your code shows a straight forward implementation of counting contents of a list equal to a given parameter. This is a good example to learn how haskell's recursion works.
An alternative implementation would be
count_instances :: Int -> [Int] -> Int
count_instances i = length . filter (==i)
that reuses already existing functions from the Prelude module. This is shorter and probably more readable.
This question already has answers here:
Equal (=) Vs left arrow (<-) symbols in haskell
(4 answers)
Closed 6 years ago.
Why can't you use substitution inside a do block?
This code works fine.
test :: (x -> x) -> [x] -> [x]
test f a = map f a
main :: IO ()
main = do
let sq x = x * x :: Int
let ret = test sq [1,2,3]
print ret
But if you remove the let's inside the do block, I got compile errors.
parse error on input ‘=’
Perhaps you need a 'let' in a 'do' block?
e.g. 'let x = 5' instead of 'x = 5'
Is "let x = y" equivalent to "x <- y" inside a do block?
So if the right hand side returns a IO something, you need to use let's (or <-) ?
I know it's a dummy question but I always get compile error with this.
eii
let is how you assign a value to a name inside a do block. let x = y is not equivalent to x <- y. Inside a do block, let desugars like this.
do let x = y
...
becomes
let x = y
in do ...
whereas
do x <- y
...
becomes
do y >>= (\x -> ...)
Bare = is only for top-level assignments, for defining functions and constants (which are a lot like 0-argument functions).
import Data.ByteString as B
import Data.ByteString.Internal as I
import Data.Bits
main = do input <- getLine
let bs = B.pack input
let intermediatebs = unfoldrN ((B.length bs)*2) unfld 0
where unfld i
|Prelude.rem i 2 == 0 = Just (top4 $ B.index bs (i/2) , i+1)
|otherwise = Just (bottom4 $ B.index bs (i/2) , i+1)
top4bits x = shiftR x 4
bottom4bits x = x .&. 0x0F
top4 x = convertASCIIword8 $ top4bits x
bottom4 x = convertASCIIword8 $ bottom4bits x
convertASCIIword8 x
|x <= 9 = I.c2w '0' + x
|otherwise = I.c2w 'A' + (x-10)
let outputbs = B.map I.w2c $ intermediatebs
in do putStrLn (outputbs)
i am getting this compilation error
The last statement in a 'do' construct must be an expression:
let intermediatebs = unfoldrN ((B.length bs) * 2) unfld 0
It's hard to see exactly what you want here. It is possible to make your code parse with only indentation changes:
import Data.ByteString as B
import Data.ByteString.Internal as I
import Data.Bits
main = do
input <- getLine
let bs = B.pack input
let intermediatebs = unfoldrN ((B.length bs)*2) unfld 0
where
unfld i
| Prelude.rem i 2 == 0 = Just (top4 $ B.index bs (i/2) , i+1)
| otherwise = Just (bottom4 $ B.index bs (i/2) , i+1)
top4bits x = shiftR x 4
bottom4bits x = x .&. 0x0F
top4 x = convertASCIIword8 $ top4bits x
bottom4 x = convertASCIIword8 $ bottom4bits x
convertASCIIword8 x
| x <= 9 = I.c2w '0' + x
| otherwise = I.c2w 'A' + (x-10)
let outputbs = B.map I.w2c $ intermediatebs
putStrLn (outputbs)
although it won't compile due to ambiguous getLine and putStrLn occurrences. You may want to import qualified where appropriate. Key observations:
Do-blocks, let-blocks etc. start from the left edge of the first thing inside them, regardless of where the keyword is itself. E.g.
do x
y
-- ^ because of where the x is, all future lines have to line up with it
let x = ...
y = ...
-- ^ if you have code appearing left of here, the let-block ends
As a consequence, I often give do and where their own line before starting a block. In the example I gave above, you can see that even if I moved the do-block into a function with a longer or shorter name, the indentation wouldn't change.
Lines in the same block that start indented are a continuation of the previous line. Guards are a continuation so need to be indented, likewise where for a let assignment needs to be indented further than the assignment itself.
The in do at the end of your block was redundant, so I removed it (alternatively, just indenting it would have worked too).
The error message is not caused by an indentation error so much as an ordering error. You seem to have inserted the where-block in the middle of your do-block. That does not work. The entire do-block, including the final expression, should come before the where block.
That said, you do have indentation error in your definitions inside your where-block: you need to indent the pattern guards.
Your outer do consists only of input <- getLine since the following token let is already less indended than input (which makes no sense anyway, but ....)
Perhaps you mean:
do input <- getLine
let ....
let ..... where
unfld ....
But one can only guess. Use indendation to make clear what items belong together, and what items are subitems of others. The style above rather obscures this. Also, you shouldn't write
foo x y z
| ..... =
because the compiler would see
foo x y z; | ... =