Let's say I have this piece of code:
data Command = Forward Integer
| Backwards Integer
doSomething givenCommand
| Forward value <- givenCommand = undefined
where calculatedValue = sqrt value
Let's say the undefined line, which would use the calculatedValue, is going to be really long and the calculatedValue calculation also much longer, so to make the code more readable, I'd like to use a where clause.
The problem is that the variable value, specified in the guard pattern match, is not in scope for the where clause.
Is there a way around this, which wouldn't force me to perform the calculation on the guard line ?
Thanks.
value is indeed not in the scope of where since it is not said that the given pattern guard will "fire". If the pattern fails, then there is no value, so that makes not much sense.
You can use a let … in … clause here:
doSomething givenCommand
| Forward value <- givenCommand = let calculatedValue = sqrt value in undefined
| … = …
you here however do not need a pattern guard, you can pattern match in the head of the doSomething function:
doSomething (Forward value) = undefined
where calculatedValue = sqrt value
doSomething (…) = …
Related
I'm trying to practice Haskell returns and datatypes. I'm trying to pass the following information into the program:
worm = 1:2:3:worm
eel = [1,2,3,1,2,3,1,2,3]
snake = 3:2:1:snake
whale = [1..100]
And i want to create a function that has a switch function to get the data and match it to its definition. For example, in Python:
def compare(str): #for one case and using string to clarify
if str == "1:2:3:worm":
return "worm"
I know the datatypes are lists but causes a lot of confusion. My code is giving me an error of Could not deduce (Num Char) Arising from use of worm
My code:
which :: [a] -> String
which x | x == [1,2,3,1,2,3,1,2,3] = "worm" | x == 3:2:1:snake = "snake" | otherwise = "F"
Is there another approach i'm missing? and why is my function giving me that error?
Two problems:
You can't have a function that returns a list of numbers sometimes and a string other times. That's literally the entire point of a strongly typed language. If you want something like that, you need to use a sum type.
You can't compare infinite lists. You can try, but your program will never finish.
I've got a problem in OCaml, I'm currently learning it but I'm quite a newbie still. I would like to make a function which is returning true if the string is empty or contains only whitespace and in the same time remove any occurence of begin and end.
I tried already this:
let isEmptyString s =
let rec empty i =
if i < 0 then true
else
let c = String.get s i in
if c = ' ' || c = '\009' then empty (pred i)
else false
in
s = Str.global_replace( Str.regexp "begin") "" s;
s = Str.global_replace( Str.regexp "end") "" s;
empty (pred (String.length s))
But obviously, this function is not working as I would like it because I obtain still begin in Formula.importNrAgentsFormula after calling it... Here is my way to call it :
while true do
let input = read_line () in
if not (isEmptyString input) then
let (nr, f) = Formula.importNrAgentsFormula input in
incr counter;
flush stdout;
match choice with
| "graph" -> printRes (Graph.isSat ~verbose:verb nr f)
| _ -> printUsage ()
else ()
done
If someone with more experiences in OCaml could spot and explain to me the error, I would be glad :)
Thanks in advance,
Best Regards.
I suggest you let your function isEmptyString (isBlankString rather?) do what it is supposed to do (just check if it contains only whitespaces or nothing), it should not modify the original string. You can do this in your loop:
while true do
let input = read_line () in
let input = Str.global_replace( Str.regexp "begin") "" input in
let input = Str.global_replace( Str.regexp "end") "" input in
if not (isEmptyString input) then
...
Edit: Sorry for the late edit, here is some additional information on your error:
If you run your function in OCaml, you will see this warning:
Warning 10: this expression should have type unit.
on the line of s = Str.global_replace( Str.regexp "begin") "" s;. That is because the = operator in OCaml is not the assignment operator in this case but the equality operator, so on this line you simply compare your two values and return a boolean. Since OCaml expects e1 in e1;e2 to return unit, you get this warning.
In OCaml, values of variables are immutable, so you can:
Use another variable as #Jason suggests: let t = Str.global_replace( Str.regexp "begin") "" s
"shadow" the old value as I suggest above: let s = Str.global_replace( Str.regexp "begin") "" s
Use a reference (a pointer to a location in memory): let s = ref "before" in s := "after", you can then access the value pointed by the reference with the !operator: !s. However, if you are learning functional programming, I suggest you try not to use any imperative features of OCaml at the beginning to discover this new paradigm and its possibilities.
As I am at work I don't have utop with me, but just from first glance, in your first one, the documentation says:
val global_replace : regexp -> string -> string -> string
That means you don't need a ";" as that is for when functions return unit and is syntactic sugar for something like
let () = print_endline("foobar")
Additionally, you need to use a let statement as you cannot just reassign the value of s. I don't recommend shadowing the variable as that's generally bad practice in functional programming. Use something like:
let t = (Str.global_replace( Str.regexp "begin") "" s)
Also, your function does two different things. The helper recursive function you wrote returns true and false which is good (I'm assuming it works). What you ultimately use it for however is what you're returning. Therefore, for the first function are you aren't really returning the string if "begin" and "end"s have been replaced. Therefore you should have the end output of your function actually a tuple of type (bool,string). Then you can match on it when you call it (e.g.
let b,s = isEmptyString "foobar" in
if not b then:
rest of your code
I believe you have the right idea for your function though.
Also in your second function is there a way for you to not use any while loops and counters? (Also hopefully your counter is implemented with references otherwise you won't have anything global). I would suggest retrying the place where you call your first function as loops and counters are core to imperative programming and not functional (which is what makes OCaml so
fun
:). If not, it's fine sometimes there are just things you can't really do in OCaml without using its imperative features. Let me know if those suggestions don't work.
I'm currently working my way through Learn You a Haskell for Great Good, and I'm trying to modify one of the code snippets in chapter nine, "Input and Output" to handle errors correctly:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else
let (Just action) = result
action args
where
dispatch :: [(String, [String] -> IO ())]
is an association list
and
errorExit :: IO ()
is some function that prints an error message.
Compiling this with GHC gives the error message
todo.hs:20:13: parse error in let binding: missing required 'in'
which (to my understanding), seems to be saying that the "let" here doesn't realise it's in a "do" block.
Adding "do" on lines five and seven (after "then" and "else" respectively), changes the error message to
todo.hs:20:13:
The last statement in a 'do' block must be an expression
let (Just action) = result
todo.hs:21:5: Not in scope: `action'.
and now, whilst I agree with the first error message, I also have that one of my variables has jumped out of scope? I've double checked my alignment, and nothing seems to be out of place.
What is the appropriate way to assign a varaible within an if clause that is within a do block?
My suggestion is to not use if in the first place, use case. By using case you get to test the value and bind the result to a variable all in one go. Like this:
main = do
(command:args) <- getArgs
case lookup command dispatch of
Nothing -> errorExit
Just action -> action args
For a more in-depth discussion on why we should prefer case over if see boolean blindness.
#svenningsson suggested the right fix. The reason your original fails is because let clauses can only appear at the top level of a do block - they're simple syntactic sugar that doesn't look into inner expressions:
do let x = 1
y
desugars to the let expression
let x = 1 in y
Alas, in a do block, an expression clause like if ... then ... else ... has no way to declare variables in the rest of the do block at all.
There are at least two possible ways to get around this.
Absorb the remainder of the do block into the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else do
let (Just action) = result
action args
(This is essentially the method #svenningsson uses in his better case version too.)
This can however get a bit awkward if the remainder of the do expression needs to be duplicated into more than one branch.
("Secret" trick: GHC (unlike standard Haskell) doesn't actually require a final, inner do block to be indented more than the outer one, which can help if the amount of indentation starts getting annoying.)
Pull the variable declaration outside the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
action <- if result == Nothing
then
errorExit
else do
let (Just action') = result
return action'
action args
Here that requires making up a new variable name, since the pattern in the let clause isn't just a simple variable.
Finally, action was always out of scope in the last line of your code, but GHC works in several stages, and if it aborts in the parsing stage, it won't check for scope errors. (For some reason it does the The last statement in a 'do' block must be an expression check at a later stage than parsing.)
Addendum: After I understood what #Sibi meant, I see that result == Nothing isn't going to work, so you cannot use if ... then ... else ... with that even with the above workarounds.
You are getting an error because you are trying to compare values of function type. When you perform the check if result == Nothing, it tries to check the equality of Nothing with the value of result which is a type of Maybe ([String] -> IO ()).
So, if you want it to properly typecheck, you have to define Eq instances for -> and that wouldn't make any sense as you are trying to compare two functions for equality.
You can also use fmap to write your code:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
print $ fmap (const args) result
When I use sub_string("abberr","habberyry") , it returns True, when obviously it should be False. The point of the function is to search for the first argument within the second one. Any ideas what's wrong?
sub_string :: (String, String) -> Bool
sub_string(_,[]) = False
sub_string([],_) = True
sub_string(a:x,b:y) | a /= b = sub_string(a:x,y)
| otherwise = sub_string(x,y)
Let me give you hints on why it's not working:
your function consumes "abber" and "habber" of the input stings on the initial phase.
Now "r" and "yry" is left.
And "r" is a subset of "yry". So it returns True. To illustrate a more simple example of your problem:
*Main> sub_string("rz","rwzf")
True
First off, you need to switch your first two lines. _ will match [] and this will matter when you're matching, say, substring "abc" "abc". Secondly, it is idiomatic Haskell to write a function with two arguments instead of one with a pair argument. So your code should start out:
substring :: String -> String -> Bool
substring [] _ = True
substring _ [] = False
substring needle (h : aystack)
| ...
Now we get to the tricky case where both of these lists are not empty. Here's the problem with recursing on substring as bs: you'll get results like "abc" being a substring of "axbxcx" (because "abc" will match 'a' first, then will look for "bc" in the rest of the string; the substring algorithm will then skip past the 'x' to look for "bc" in "bxcx", which will match 'b' and look for "c" in "xcx", which will return True.
Instead your condition needs to be more thorough. If you're willing to use functions from Data.List this is:
| isPrefixOf needle (h : aystack) = True
| otherwise = substring needle aystack
Otherwise you need to write your own isPrefixOf, for example:
isPrefixOf needle haystack = needle == take (length needle) haystack
As Sibi already pointed out, your function tests for subsequence. Review the previous exercise, it is probably isPrefixof (hackage documentation), which is just a fancy way of saying startsWith, which looks very similar to the function you wrote.
If that is not the previous exercise, do that now!
Then write sub_string in terms of isPrefixOf:
sub_string (x, b:y) = isPrefixOf ... ?? ???
Fill in the dots and "?" yourself.
I am fairly new to Haskell but do get most of the basics. However there is one thing that I just cannot figure out. Consider my example below:
example :: Int -> Int
example (n+1) = .....
The (n+1) part of this example somehow prevents the input of negative numbers but I cannot understand how. For example.. If the input were (-5) I would expect n to just be (-6) since (-6 + 1) is (-5). The output when testing is as follows:
Program error: pattern match failure: example (-5)
Can anyone explain to me why this does not accept negative numbers?
That's just how n+k patterns are defined to work:
Matching an n+k pattern (where n is a variable and k is a positive integer literal) against a value v succeeds if x >= k, resulting in the binding of n to x - k, and fails otherwise.
The point of n+k patterns is to perform induction, so you need to complete the example with a base case (k-1, or 0 in this case), and decide whether a parameter less than that would be an error or not. Like this:
example (n+1) = ...
example 0 = ...
The semantics that you're essentially asking for would be fairly pointless and redundant — you could just say
example n = let n' = n-1 in ...
to achieve the same effect. The point of a pattern is to fail sometimes.