Related
In my code I call the validateFEN function with a FEN String. A Fen string looks like this for example:
",w84,w41,w56,w170,w56,w41,w84,/,,w24,w40,w17,w40,w48,,/,,,w16,w16,w16,,,/,,,,,,,,/,,,,,,,,/,,,,,,,,/,,,b1,b1,b1,,,/,,b3,b130,b17,b130,b129,,/,b69,b146,b131,b170,b131,b146,b69,"
The function should take the string and check if it's a FEN string.
How does it know if it's a FEN string? -> My string has 9 rows and 9 columns. I don't need to check if the pieces (example: w86) are at their right position.
validateFEN' b = help3 (filter (\x -> x == ',' || x == '/' ) b)
help3 b = (if help1 b == True then (if head (drop 8 b) == '/' then help3 (drop 9 b) else False) else False )
help1 b = help2 (take 8 b)
help2 b = foldr (+) 0 (map (\x -> if x == ',' then 1 else 0 )b) == 8
Why do I keep getting the error for a empty list?
Exception: Prelude.head: empty list
I understand that with my code there is no stop. The program doesn't know when the string is "correct".
Is there a shorter simpler way of doing this?
One way to reuse existing library functions to make this clearer would be to use stripPrefix.
help3 s = case stripPrefix ",,,,,,,,/" s of
Nothing -> False
Just s' -> help3 s'
Of course, you still need to handle the final case, where there is no terminating /. This can be done with a single extra clause:
help3 ",,,,,,,," = True
help3 s = {- ... -}
You might want to ponder whether validateFEN' should have a similar special case for the empty string.
BUT I would strongly suggest simply not implementing validateFEN' in the first place. My guess is that the plan is something like this:
Check if a string is valid FEN.
Process the string, assuming FEN-ness.
Instead, I recommend the following approach:
Parse the string into a native data structure that represents the information available in a FEN string.
Process the native structure.
Step 1, if written with standard parsing solutions, will "accidentally" validate the string -- i.e. running your parser will return something like Either Error FEN, which you can pattern match on to either discover that the string is invalid or that it is valid and has been turned into a more idiomatic representation.
I tried making a function that as in the title takes 2 arguments, a number that specifies how many times the number must occur and a list that we are working on, I made a function that counts number of appearances of given number in a list and I tried using it in my main function, but I cannot comprehend how the if else and indentations work in Haskell, it's so much harder fixing errors than in other languages, i think that I'm missing else statement but even so I don't know that to put in there
count el list = count el list 0
where count el list output
| list==[] = output
| head(list)==el = count el (tail(list)) output+1
| otherwise = count el (tail(list)) output
moreThan :: Eq a => Int -> [a] -> [a]
moreThan a [] = []
moreThan a list = moreThan a list output i
where moreThan a list [] 0
if i == length (list)
then output
else if elem (list!!i) output
then moreThan a list output i+1
else if (count (list!!i) list) >= a
then moreThan a list (output ++ [list!!i]) i+1
All I get right now is
parse error (possibly incorrect indentation or mismatched brackets)
You just forgot the = sign and some brackets, and the final else case. But also you switched the order of the internal function declaration and call:
moreThan :: Eq a => Int -> [a] -> [a]
moreThan a [] = []
moreThan a list = go a list [] 0 -- call
where go a list output i = -- declaration =
if i == length (list)
then output
else if elem (list!!i) output
then go a list output (i+1) -- (i+1) !
else if (count (list!!i) list) >= a
then go a list (output ++ [list!!i]) (i+1) -- (i+1) !
else
undefined
I did rename your internal function as go, as is the custom.
As to how to go about fixing errors in general, just read the error messages, slowly, and carefully -- they usually say what went wrong and where.
That takes care of the syntax issues that you asked about.
As to what to put in the missing else clause, you've just dealt with this issue in the line above it -- you include the ith element in the output if its count in the list is greater than or equal to the given parameter, a. What to do else, we say in the else clause.
And that is, most probably, to not include that element in the output:
then go a list (output ++ [list!!i]) (i+1)
else ---------------------
undefined
So, just keep the output as it is, there, instead of the outlined part, and put that line instead of the undefined.
More importantly, accessing list elements via an index is an anti-pattern, it is much better to "slide along" by taking a tail at each recursive step, and always deal with the head element only, like you do in your count code (but preferably using the pattern matching, not those functions directly). That way our code becomes linear instead of quadratic as it is now.
Will Ness's answer is correct. I just wanted to offer some general advice for Haskell and some tips for improving your code.
First, I would always avoid using guards. The syntax is quite inconsistent with Haskell's usual fare, and guards aren't composable in the same way that other Haskell syntax is. If I were you, I'd stick to using let, if/then/else, and pattern matching.
Secondly, an if statement in Haskell is very often not the right answer. In many cases, it's better to avoid using if statements entirely (or at least as much as possible). For example, a more readable version of count would look like this:
count el list = go list 0 where
go [] output = output
go (x:xs) output = go xs (if x == el
then 1 + output
else output)
However, this code is still flawed because it is not properly strict in output. For example, consider the evaluation of the expression count 1 [1, 1, 1, 1], which proceeds as follows:
count 1 [1, 1, 1, 1]
go [1, 1, 1, 1] 0
go [1, 1, 1] (1 + 0)
go [1, 1] (1 + (1 + 0))
go [1] (1 + (1 + (1 + 0)))
go [] (1 + (1 + (1 + (1 + 0))))
(1 + (1 + (1 + (1 + 0))))
(1 + (1 + 2))
(1 + 3)
4
Notice the ballooning space usage of this evaluation. We need to force go to make sure output is evaluated before it makes a recursive call. We can do this using seq. The expression seq a b is evaluated as follows: first, a is partially evaluated. Then, seq a b evaluates to b. For the case of numbers, "partially evaluated" is the same as being totally evaluated.
So the code should in fact be
count el list = go list 0 where
go [] output = output
go (x:xs) output =
let new_output = if x == el
then 1 + output
else output
in seq new_output (go xs new_output)
Using this definition, we can again trace the execution:
go [1, 1, 1, 1] 0
go [1, 1, 1] 1
go [1, 1] 2
go [1] 3
go [] 4
4
which is a more efficient way to evaluate the expression. Without using library functions, this is basically as good as it gets for writing the count function.
But we're actually using a very common pattern - a pattern so common, there is a higher-order function named for it. We're using foldl' (which must be imported from Data.List using the statement import Data.List (foldl')). This function has the following definition:
foldl' :: (b -> a -> b) -> b -> [a] -> b
foldl' f = go where
go output [] = output
go output (x:xs) =
let new_output = f output x
in seq new_output (go new_output xs)
So we can further rewrite our count function as
count el list = foldl' f 0 list where
f output x = if x == el
then 1 + output
else output
This is good, but we can actually improve even further on this code by breaking up the count step into two parts.
count el list should be the number of times el occurs in list. We can break this computation up into two conceptual steps. First, construct the list list', which consists of all the elements in list which are equal to el. Then, compute the length of list'.
In code:
count el list = length (filter (el ==) list)
This is, in my view, the most readable version yet. And it is also just as efficient as the foldl' version of count because of laziness. Here, Haskell's length function takes care of finding the optimal way to do the counting part of count, while the filter (el ==) takes care of the part of the loop where we check whether to increment output. In general, if you're iterating over a list and have an if P x statement, you can very often replace this with a call to filter P.
We can rewrite this one more time in "point-free style" as
count el = length . filter (el ==)
which is most likely how the function would be written in a library. . refers to function composition. The meaning of this is as follows:
To apply the function count el to a list, we first filter the list to keep only the elements which el ==, and then take the length.
Incidentally, the filter function is exactly what we need to write moreThan compactly:
moreThan a list = filter occursOften list where
occursOften x = count x list >= a
Moral of the story: use higher-order functions whenever possible.
Whenever you solve a list problem in Haskell, the first tool you should reach for is functions defined in Data.List, especially map, foldl'/foldr, filter, and concatMap. Most list problems come down to map/fold/filter. These should be your go-to replacement for loops. If you're replacing a nested loop, you should use concatMap.
in a functional way, ;)
moreThan n xs = nub $ concat [ x | x <- ( group(sort(xs))), length x > n ]
... or in a fancy way, lol
moreThan n xs = map head [ x | x <- ( group(sort(xs))), length x > n ]
...
mt1 n xs = [ head x | x <- ( group(sort(xs))), length x > n ]
I am new to SML. I tried to create and test the following function below, but I received an error. I do not know what is the problem.
fun isOld(pFirstTuple: int*int*int, pSecondTuple: int*int*int) =
if (#1 pFirstTuple) < (#1 pSecondTuple)
then
true
if (#1 pFirstTuple) = (#1 pSecondTuple)
then
if (#2 pFirstTuple) < (#2 pSecondTuple)
then
true
else
false
I have tried this command "val p = isOld((8,9,10),(10,11,12))", but it showed me the following error Unbound variable or constructor. How do I fix this?
Here's what your code looks like, stripped down by ignoring various subexpressions (replacing them with A, B, and C)
if A
then true
if B
then if C
then true
else false
You're making extensive use of if/then/else, but the syntax is not quite correct. In SML, every if must have both a then and else clause associated with it. Here's my guess at what you actually meant:
if A
then true
else if B
then if C
then true
else false
else false
This is starting to get quite messy---but you can clean it up with boolean logic. Notice, for example, that if X then true else false means exactly the same thing as simply writing X, because both expressions are type bool and will always evaluate to the same boolean, regardless of what X is. You can extend this reasoning to see that
if X then true else Y is equivalent to X orelse Y.
if X then Y else false is equivalent to X andalso Y.
With these ideas, we can clean up your code considerably:
A orelse (B andalso C)
I read in a few tutorials that if a then b else c stands for match a with true => b | false => c end. However the former very strangely does not check the type of a, while the latter of course makes sure that a is a boolean. For instance,
Coq < Check if nil then 1 else 2.
if nil then 1 else 2
: nat
where
?A : [ |- Type]
Coq < Check match nil with true => 1 | false => 2 end.
Toplevel input, characters 33-38:
> Check match nil with true => 1 | false => 2 end.
> ^^^^^
Error: Found a constructor of inductive type bool while
a constructor of list is expected.
Why is if ... then ... else ... allowing its first argument to be anything else than a non-boolean? Is there some overloading going on? (Locate "if". gives no result.)
Let me quote the Coq Reference manual:
For inductive types with exactly two constructors and for pattern-matchings expressions which do not depend on the arguments of the constructors, it is possible to use a if ... then ... else ... notation. More generally, for an inductive type with constructors C1 and C2, we have the following equivalence:
if term [dep_ret_type] then term1 else term2
is equivalent to
match term [dep_ret_type] with
| C1 _ ... _ => term1 (* we cannot bind the arguments *)
| C2 _ ... _ => term2
end
As you can see, the first constructor is treated as true value. Here is an example:
Definition is_empty {A : Type} (xs : list A) : bool :=
if xs then true else false.
This is what I want to do:
INPUT: [1,2,3,-1,-2,-3]
OUTPUT:[1,1,1,-1,-1,-1]
I tried this:
signNum (x:n) = map(if x>0
then 1
else -1)n
Can anyone tell me where I've made a mistake in the logic?
The first problem is that map expects a function. So you have to wrap your if statement in a lambda. However, this will still not do exactly what you want. Instead of breaking the list into its head and tail, your really want to map your function over the whole list.
Remember that map just takes a function and applies it to each element. Since you want to turn each element into either 1 or -1, you just need to map the appropriate function over your list.
So in the end, you get:
sigNum ls = map (\ x -> if x > 0 then 1 else - 1) ls
In this case, it is probably easier to break the function down into smaller parts.
At the very lowest level, one can compute the signum of a single number, i.e.:
signum :: (Num a, Ord a) => a -> a
signum x = if x > 0 then 1 else -1
Once you have this, you can then use it on a list of numbers, like you would for any function:
signNum ls = map signum ls
(p.s. what is signum 0 meant to be? Your current definition has signum 0 = -1.
If you need to expand the function to include this case, it might be better to use guards:
signum x | x < 0 = -1
| x == 0 = 0
| otherwise = 1
or a case statement:
signum x = case compare x 0 of
LT -> -1
EQ -> 0
GT -> 1
)
Your comments suggest you'd like to be able to do this with a comprehension.
How to use a comprehension
If you do want to do this with a comprehension, you can do
signNum ls = [ if x>0 then 1 else -1| x <- ls ]
How not to use a comprehension
...but you can't put the condition on the right hand side
brokenSignNum ls = [ 1| x <- ls, x > 0 ]
Because putting a condition on the right hand side removes anything that
doesn't satisfy the condition - all your negatives get ignored! This would
shorten your list rather than replace the elements. Let's try
brokenSignNum2 ls = [ 1| x <- ls, x > 0 ] ++ [ -1| x <- ls, x <= 0 ]
This has the same length as your original list but all the positives are at the front.
Summary: you have to put this conditional expression on the left hand side
becuase that's the only place substitution can happen - on the right hand side it does deletion.
Is zero negative?
Note that your if statement counts 0 as negative. Are you sure you want that? Perhaps you'd be better with defining the sign of a number seperately:
sign x | x == 0 = 0 -- if x is zero, use zero
| x > 0 = 1 -- use 1 for positives
| x < 0 = -1 -- use -1 for negatives
workingSignNum1 ls = [sign x | x <- ls]
But sign is (almost) the same as the function signum, so we may as well use that
workingSignNum2 ls = [signum x | x <- ls]
Making it tidier
Now that's a lot of syntax for what basically means "replace x with sign x all along the list ls". We do that kind of thing a lot, so we could write a function to do it:
replaceUsing :: (a -> b) -> [a] -> [b]
replaceUsing f xs = [f x | x <- xs]
but there's already a function that does that! It's called map. So we can use map on our list:
quiteSlickSignNum :: Num a => [a] -> [a]
quiteSlickSignNum ls = map signum ls
or even slicker:
slickSignNum :: Num a => [a] -> [a]
slickSignNum = map signum
which is how I would have defined it.
Why did you say sign was almost the same as signum?
sign takes a number and returns a number, 1, 0, or -1, but what's the type of 1?
Well, 1 has the type Num a => a so you can use it with any numeric type. This means
sign takes any type of number and returns any type of number, so its type is
sign :: (Num a,Num b) => a -> b
so my version of sign can give you a different type. If you try it out, you'll find that 3 * sign 4.5 gives you 3, not 3.0, so you can get an Integer out of it, but also if you do 3.14 * sign 7.4, you get 3.14, so you can get a decimal type too. By contrast,
signum :: Num a => a -> a
so it can only give you back the type you gave it - 3 * signum 4.5 gives you 3.0.
The error message "no instance for Num" is one of the trickiest for new Haskellers to decipher. First, here's the fully polymorphic type signature for the function you are trying to write (I added this to the source file in order to get the same error as you):
signNum :: (Ord a, Num a) => [a] -> [a]
Finding the error
Now, the compile error message says:
Could not deduce (Num (a -> a)) from the context (Ord a, Num a)
arising from the literal `1' at prog.hs:3:17
Notice that the error message gives us the location of the problem. It says that "the literal 1" at file_name.hs:line_number:column_number is the problem.
signNum (x:n) = map(if x>0
then 1 -- <-- here's the problem! (according to that message)
else -1)n
Understanding the error
Now, the error message also suggests some possible fixes, but whenever you run into "no instance for Num", the suggested "possible fixes" are almost always wrong, so ignore them. (I wish GHC would provide better error messages for Num-related stuff like this).
Recall what the error message said:
Could not deduce (Num (a -> a)) ... arising from the literal `1' ...
What this means is that you put a literal 1 somewhere where the context expected something of type
a -> a. 1 is obviously not a function, so either the context is wrong, or the number 1 is wrong.
So what is the context of the literal 1?
Finding the error (precisely)
(if x > 0
then <<hole>>
else -1)
If statements in Haskell produce a value. The branches of an if statement must have the same type, and the type of the if statement is determined by the type of the branches.
Here, the other branch has the value -1, which is a number. So we therefore expect the <<hole>> to have the same type: a number. Well, this obviously isn't the problem (since 1 is a number), so let's look at the context of that expression.
map <<hole>> n
The map function expects a function as its first argument. However, we know the <<hole>> will produce a number. Eureka! Here's the discrepancy: we're giving map a number where it expects a function.
Correcting the error
The obvious solution -- now that we know precisely what and where the problem is -- is to give map a function, rather than a number. See the various other answers for details.