My situation:
In my code, a value xID seems to be variable in case ~ of structure.
import Debug.Trace
data I = I
{ iID :: Int } deriving Show
data C = C
{ i :: I} deriving Show
x = I 0
aC2 = C (I 2)
aC3 = C (I 3)
aC5 = C (I 5)
xID = iID x
cConverter aC =
trace ((show cIID) ++ (if cIID == xID then "==" else "/=") ++ (show xID) ++ " when " ++ (show x)) $
"Point: " ++ pID
where
pID :: String
pID =
case cIID of
xID -> trace ((show cIID) ++ (if cIID == xID then "==" else "/=") ++ (show xID) ++ " when " ++ (show x)) "X"
_ -> show cIID
cIID = iID . i $ aC
-- xID = iID x
What I expect
I expected that when I run cConverter aC2, I'll get "2" because 2 in aC2 = C (I 2) is not equal to 0 in x = I 0.
What happens
However, I've faced the strange result when I run cConvert aC2 like:
Main> cConverter aC2
"2/=0 when I {iID = 0}
Point: 2==2 when I {iID = 0}
X"
Why I get "X" instead of "2"?
More precisely, Why xID is 2 when cIID is 2, and xID is 3 when cIID is 3?
I think xID always be 0 in this code, but does xID means something other when I use this in the condition of the case?
Clear sample
Here is more clear code without debugging message
data I = I
{ iID :: Int } deriving Show
data C = C
{ i :: I} deriving Show
x = I 0
aC2 = C (I 2)
aC3 = C (I 3)
aC5 = C (I 5)
xID = iID x
cConverter aC =
"Point: " ++ pID
where
pID :: String
pID =
case cIID of
xID -> "X"
_ -> show cIID
cIID = iID . i $ aC
-- xID = iID x
Point 1
GHCi warns me like:
Bug.hs:22:7: Warning:
Pattern match(es) are overlapped
In a case alternative: _ -> ...
It seems to be xID overlaps _.
But why xID overlaps hole?
Anyway, I avoid this problem by using a guard instead of case.
However, I could not understand what happens with my code.
The case
case cIID of
xID -> ...
_ -> ...
introduces a new local variable named xID, which is unrelated to the global xID. Further, since it is a variable it catches everything: the branch _ -> ... will never be taken.
Use this instead:
case cIID of
xID' | xID' == xID -> ...
_ -> ...
or, more simply,
if cIID == xID
then ...
else ...
About "why" it works in this way:
Consider the code
foo :: Either Int String -> Int
foo e = case e of
Left x -> x
Right y -> length y
This is a nice total function: it will always return an Int whatever is the value of the argument e.
Now suppose I add to the code, much later on,
x :: Int
x = 42
This should NOT break foo! Yet, if the x in Left x is now interpreted to be 42, then function foo will crash on e.g. Left 43.
For this reason, pattern matching always introduces new variables, it never performs equality checks with pre-existing variables. To do that, use a guard like x | x == y -> ....
Related
I need to swap blank space with letter from "moves" and each time I swap it I need to continue with another one from moves. I get Couldn't match expected type, even though I just want to return value x when it doesn't meet condition.
Error message:
[1 of 1] Compiling Main ( puzzlesh.hs, interpreted )
puzzlesh.hs:19:43: error:
• Couldn't match expected type ‘Int -> a’ with actual type ‘Char’
• In the expression: x
In the expression: if x == ' ' then repl x else x
In an equation for ‘eval’: eval x = if x == ' ' then repl x else x
• Relevant bindings include
eval :: Char -> Int -> a (bound at puzzlesh.hs:19:5)
repl :: forall p. p -> Int -> a (bound at puzzlesh.hs:20:5)
moves :: [a] (bound at puzzlesh.hs:16:9)
p :: t [Char] -> [a] -> [Int -> a] (bound at puzzlesh.hs:16:1)
|
19 | eval x = if x == ' ' then repl x else x
| ^
Failed, no modules loaded.
Code:
import Data.Char ( intToDigit )
sample :: [String]
sample = ["AC DE",
"FBHIJ",
"KGLNO",
"PQMRS",
"UVWXT"]
moves = "CBGLMRST"
type Result = [String]
pp :: Result -> IO ()
pp x = putStr (concat (map (++"\n") x))
p input moves = [eval x | x <- (concat input)]
where
c = 1
eval x = if x == ' ' then repl x else x
repl x count = moves !! count
count c = c + 1
I need to take character from moves, replace it onto blank space and do this till moves is []
Desired output:
ABCDE
FGHIJ
KLMNO
PQRST
UVWX
As with most problems, the key is to break it down into smaller problems. Your string that encodes character swaps: can we break that into pairs?
Yes, we just need to create a tuple from the first two elements in the list, and then add that to the result of calling pairs on the tail of the list.
pairs :: [a] -> [(a, a)]
pairs (x:tl#(y:_)) = (x, y) : pairs tl
pairs _ = []
If we try this with a string.
Prelude> pairs "CBGLMRST"
[('C','B'),('B','G'),('G','L'),('L','M'),('M','R'),('R','S'),('S','T')]
But you want a blank space swapped with the first character:
Prelude> pairs $ " " ++ "CBGLMRST"
[(' ','C'),('C','B'),('B','G'),('G','L'),('L','M'),('M','R'),('R','S'),('S','T')]
Now you have a lookup table with original characters and their replacements and the rest is straightforward. Just map a lookup on this table over each character in each string in the list.
Because you never touch any letter in the original strings more than once, you won't have to worry about double replacements.
Prelude> s = ["AC DE","FBHIJ","KGLNO","PQMRS","UVWXT"]
Prelude> r = "CBGLMRST"
Prelude> r' = " " ++ r
Prelude> p = pairs r'
Prelude> [[case lookup c p of {Just r -> r; _ -> c} | c <- s'] | s' <- s]
["ABCDE","FGHIJ","KLMNO","PQRST","UVWXT"]
As an exercise in learning Haskell I've written an interpreter for the CESIL language (an old, very basic, educational low level language). It works, but compared to implementations I've written in other compiled languages it's very slow, even when compiled with -O2, and only a little faster than Python. Timing a large CESIL program with time gives:
Haskell:
real 0m0.346s
user 0m0.199s
sys 0m0.016s
Go:
real 0m0.243s
user 0m0.003s
sys 0m0.007s
Python:
real 0m0.414s
user 0m0.387s
sys 0m0.004s
Here's the main execution part of the code where most of the time is spent, and which I would like to speed up. I'm new to Haskell, and I'm sure there are better, cleaner ways of writing some of this, but my main concern at the moment is the speed. Hopefully I've included enough to make sense:
-- Define the computer state
data Computer =
Computer
{ program :: Array Integer Instruction
, dataVals :: [Integer]
, ram :: Map.Map String Integer
, acc :: Integer
, pc :: Integer
, steps :: Integer
, halted :: Bool
}
-- Initialise the computer and run the program
runProgram ::
Array Integer Instruction -> [Integer] -> Params -> ExceptT String IO ()
runProgram pr dv pars = do
let comp =
Computer
{ program = pr
, dataVals = dv
, ram = Map.empty
, acc = 0
, pc = 0
, steps = 0
, halted = False
}
comp' <- execute comp pars
if countSteps pars
then liftIO . putStrLn $ "Steps executed: " ++ (show $ steps comp')
else return ()
-- Main execution "loop"
execute :: Computer -> Params -> ExceptT String IO Computer
execute comp pars = do
liftEither $ checkPC comp
(comp', output) <- liftEither $ step comp
liftIO $ putStr output
case () of
_
| halted comp' -> return comp'
| Just (steps comp') == maxSteps pars -> do
liftIO $
putStrLn $
"Execution halted after " ++ (show $ steps comp') ++ " steps."
return comp'
| otherwise -> execute comp' pars
-- Check program counter is in range.
checkPC :: Computer -> Either String ()
checkPC comp =
if pc comp >= (toInteger . length . program $ comp) || pc comp < 0
then Left $ "PC OUT OF RANGE: " ++ (show $ pc comp) ++ "\n"
else Right ()
-- Execute a single step/cycle
step :: Computer -> Either String (Computer, String)
step comp = do
let Instruction lineNo label opCode operand =
program comp ! (fromIntegral . pc $ comp)
comp' = comp {pc = pc comp + 1, steps = steps comp + 1}
case opCode of
IN ->
if null $ dataVals comp
then Left $ "Data exhausted at line " ++ show lineNo ++ "\n"
else let a:dv = dataVals comp
in Right (comp {acc = a, dataVals = dv, pc = pc comp + 1}, "")
OUT -> Right (comp', printf "%8d" $ acc comp)
LINE -> Right (comp', "\n")
PRINT ->
let TextOperand s = operand
in Right (comp', s)
HALT -> Right (comp' {halted = True}, "")
LOAD -> do
n <- getVal operand comp' lineNo
Right (comp' {acc = n}, "")
STORE ->
let SymbolOperand s = operand
ram' = Map.insert s (acc comp') (ram comp')
in Right (comp' {ram = ram'}, "")
ADD -> do
n <- getVal operand comp' lineNo
let a = acc comp' + n
Right (comp' {acc = a}, "")
SUBTRACT -> do
n <- getVal operand comp' lineNo
let a = acc comp' - n
Right (comp' {acc = a}, "")
MULTIPLY -> do
n <- getVal operand comp' lineNo
let a = acc comp' * n
Right (comp' {acc = a}, "")
DIVIDE -> do
n <- getVal operand comp' lineNo
if n == 0
then Left $ "Divide by zero error at line " ++ show lineNo ++ "\n"
else let a = acc comp' `div` n
in Right (comp' {acc = a}, "")
JUMP -> do
let AddrOperand a = operand
Right (comp' {pc = a}, "")
JIZERO -> do
let AddrOperand a = operand
comp'' =
if acc comp' == 0
then comp' {pc = a}
else comp'
Right (comp'', "")
JINEG -> do
let AddrOperand a = operand
comp'' =
if acc comp' < 0
then comp' {pc = a}
else comp'
Right (comp'', "")
NoOp -> Right (comp' {steps = steps comp}, "")
-- Get the value of a numeric operand, which may be a literal constant
-- or a reference to a stored variable.
getVal :: Operand -> Computer -> LineNo -> Either String Integer
getVal (ValueOperand (Left n)) _ _ = Right n
getVal (ValueOperand (Right s)) comp lineNo =
case Map.lookup s $ ram comp of
Just n -> Right n
Nothing ->
Left $ "Unknown variable: '" ++ s ++ "' at line " ++ show lineNo ++ "\n"
As others have pointed out, you're not actually comparing apples to apples here - you've chosen types which are well known to be inefficient - String, Integer, []. So, in order of things to try:
Profile your code - we can make guesses about what might be slow but only the program can tell us if that's true. GHC 9.2 has made some nice improvements in profiling optimised code, see https://well-typed.com/blog/2022/05/hasura-supports-haskell-tooling/. Covering how to do profiling is a topic too large to go into here, but there is a lot of documentation available: https://downloads.haskell.org/ghc/latest/docs/html/users_guide/profiling.html
Try basic improvements to the types you use, stop using String and switch to ByteString, use Int instead of Integer (you'll lose the ability to do arbitrary precision calculations but I assume CESIL was never intended to do that). Using a HashMap instead of a Map might see some improvements, but you'll have to benchmark to know.
Be more explicit about strictness - most, if not all, of the fields in the Computer type could be made strict to tell the compiler "Always evaluate this, there's no need for it to be lazy":
data Computer =
Computer
{ program :: Array Int Instruction
, dataVals :: [Int]
, ram :: !HashMap ByteString Int
, acc :: !Int
, pc :: !Int
, steps :: !Int
, halted :: Bool
}
Doing this will also remove many of the conversions you had between Integer and Int which are unnecessary (unless you really want your program to work with programs with more than 9,223,372,036,854,775,807 instructions)
I wanted to Print to A pascal Triangle for a given Length.
main = do
l_str <- getLine
let l_int = read $ l_str :: Int
let why = print_row l_int 0
print why
return ()
print_row x y
| (x < y) = " "
| otherwise = (print_column y 0 ) ++ "\n" ++ print_row x (y+1)
print_column y r
| (y < r) = ""
| otherwise = (show $ fact y r ) ++ print_column y (r+1)
fact n r
| (n >= r) = truncate $ (fact' n)/((fact' (n-r))*(fact' r))
fact' n
| (n >= 0) = product [1..n]
I have checked all my functions "print_row" ,"print_column" everything works fine.
I am getting this error:
PascalTriangle.hs:4:17:
No instance for (RealFrac Int) arising from a use of ‘fact’
In the expression: fact l_int 0
In an equation for ‘why’: why = fact l_int 0
In the expression:
do { l_str <- getLine;
let l_int = ...;
let why = fact l_int 0;
print why;
.... }
I am not able Understand anything about this error.The pogram works fine when I use a constant instead of l_int in line 4.Like let why = print_row 4 0.
You need to use div instead of /.
div will take two Integral values and return another Integral value - e.g. div 5 2 == 2. Then you'll also need to get rid of the truncate call.
/ does "floating point" division.
fromIntegral will convert an Integral value to any other Num type.
This is to take a number, get its factorial and double it, however because of the base case if you input 0 it gives 2 as the answer so in order to bypass it i used an if statement, but get the error
parse error on input ‘if’. Really appreciate if you guys could help :)
fact :: Int -> Int
fact 0 = 1
fact n = n * fact(n-1)
doub :: Int -> Int
doub r = 2 * r
factorialDouble :: IO()
factorialDouble = do
putStr "Enter a Value: "
x <- getLine
let num = (read x) :: Int
if (num == 0) then error "factorial of zero is 0"
else let y = doub (fact num)
putStrLn ("the double of factorial of " ++ x ++ " is " ++ (show y))
I've spotted two issues
that should be addressed
You have a let that has no continuation:
(else let y = doub (fact num) ...).
Because you're not inside a do, you would probably want to change it into a let ... in statement.
Your if is indented too far in. It should be under the let.
I've corrected what I mentioned and the code works for me...
fact :: Int -> Int
fact 0 = 1
fact n = n * fact(n-1)
doub :: Int -> Int
doub r = 2 * r
factorialDouble :: IO ()
factorialDouble = do
putStr "Enter a Value: "
x <- getLine
let num = (read x) :: Int
if num == 0 then (error "factorial of zero is 0")
else let y = doub (fact num)
in putStrLn ("the double of factorial of " ++ x ++ " is " ++ (show y))
this is an expansion to my last question here: basic haskell : Copying elements
however when an invalid input is added then I want it to print out an error message saying "negative value" or something similar. Is this possible in haskell?
working code:
copy :: Int->a->[a]
copy 0 _ = []
copy y a = [a]++(copy (y-1) a)
final line:
copy b c = error "negative value"
Because partial functions make me sad, I'd suggest doing something more along the lines of
copy :: Int -> a -> Maybe [a]
copy 0 _ = Just []
copy n a | n < 0 = Nothing
| otherwise = fmap (a:) (copy (n-1) a)
We've swapped out that if for a "guard"
foo bar | baz = quux
| ...
is just
foo bar = if baz then quux else ...
Note that I also changed your code a little,
[a] ++ copy (y-1) a ====> fmap (a:) (copy (y-1) a)
You can think of (:) as append.
1 : [2, 3] ==> [1, 2, 3]
It's the preferred alternative to [1] ++ [2, 3]. Say it out loud as "cons", like "construct". We can write this with an operator section
(a:) ==> \x -> a : x
Next we use this wonky fmap function. Think of fmap like this
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
So it unwraps a Just and applies a function before rewrapping the result. So our final code returns Nothing if our number is negative, otherwise, just the list.
Why aren't I recommending error? Well because error will blow up your whole program with pretty minimal information and it's a bad idea to try to catch it. Haskell doesn't even mandate that it's possible to do so, GHC just implements error in such a way that it's possible. In other words, you have little chance to recover.
This isn't a big deal for 10 lines of code, but I've spent upwards of 6 hours searching for the offending call to a function using error. It's much faster to debug and more idiomatic haskell.
You can do this with guards
copy :: Int -> a -> [a]
copy n x
| n < 0 = error "negative value"
| n == 0 = []
| otherwise = x : copy (n - 1) x
However, if this fails then it will likely crash your program. A better way is to use the Maybe type:
copySafe :: Int -> a -> Maybe [a]
copySafe n x
| n < 0 = Nothing
| otherwise = Just (copy n x)
Then you can use it as
main = do
putStrLn "Enter a number:"
nStr <- getLine
let n = read nStr :: Int
maybeXs = copySafe n n
case maybeXs of
Nothing -> putStrLn "You entered a negative number!"
Just xs -> print xs
This style forces you to consider both cases of copySafe, either it can fail on a negative value or it can return a valid list. It doesn't crash your program and the error handling is enforced by the type system.
look at http://www.haskell.org/haskellwiki/Error_vs._Exception
for example
copy b c = if c > b then error "negativ value"