I am new to Haskell; just for a project I am supposed to understand the source code: I have been looking at the Udemy courses, "Learn you a Haskell", and others but still struggling at this point: The snippet of code is for reporting bugs.
I want to know what "Named Instruction" stands for, and what the snippet of code does:
maybeReportBug :: Named Instruction -> Int -> Checker Uninits UninitBug ()
maybeReportBug ni lineno = do
s0 <- getState
let allTainted = tainted s0
allFields = bitfields s0
unless (null allTainted) $ do
let names = catMaybes $ map nameOf $ getOperands ni
where:
blankUninit :: Uninits
blankUninit = Uninits S.empty M.empty S.empty
data Uninits = Uninits { uninits :: S.Set Name
, tainted :: M.Map Operand (S.Set Name)
, bitfields :: S.Set Name
}
deriving (Eq, Ord, Show)
And where
getState :: Checker a b a
getState = curState `liftM` get
And where
newtype Checker a b c = Checker { unChecker :: StateT (CheckerState a b) IO c }
deriving (Functor, Applicative, Monad, MonadState (CheckerState a b), MonadIO)
CodePudding user response:
Let me try to answer the question asked in the title - the code you are trying to understand is very complicated for a beginner, and Haskell is very much unlike any programming language that you have seen before.
$
- this is the precedence operator.
The parser in Haskell parses the code from left to right. So, if I want to print out a factorial:
print factorial 6
How does Haskell understand this? Haskell starts with print
, and then looks for the arguments to print. Haskell reads factorial
but doesn't know how to print one of those and emits an error message.
We should have put parentheses around factorial 6
. That would work, but be a bit ugly.
print (factorial 6)
Instead we might use $
(not to be confused with <$> which is an abbreviation for fmap
and very different). What $
does is to defer the left hand side until the right hand side is done. So we could say:
print $ factorial 6.
Now Haskell will wait until factorial 6 is done before trying to print it. And it looks better than a lot of parentheses.
do
- monad sugaring
What you need to understand is that the code that Haskell is actually running is very different to the code that you type in.
If you have a list you can extract the contents using the >>=
operator. This gives me raw data that I can process, for example multiplying the data by two, before turning it back into a list with return
.
[1,2,3] >>= (\x -> return $ 2*x)
This is workable code but ugly.
All of Haskell's code is like this, and you can tell Haskell to show you these things. However, most of the time we're quite happy to not see this. Hence, we sugar
the code, that is to say we find an easier way of saying what we want to say, and let Haskell figure it out:
main = do
putStr "What is your name: "
name <- readLine
putStrLn $ "Hello " name
Which is equivalent to this de-sugared equivalent:
main =
putStr "What is your name: " >>
getLine >>= (\name ->
putStrLn $ "Hello " name)
The first one looks like Python, the second one is more confusing - and if the code goes on a bit, with branches, the de-sugared version gets harder and harder to write and maintain.
unless
- make a decision
There are many ways of making a decision in Haskell, and two of them are when
and unless
.
Both take a Boolean value as the first parameter. The difference is that when
does something when the value is True, and unless
does something when the value is False. Unlike if .. then .. else
, when
and unless
don't need both branches of the decision.
import Control.Monad
main = do
when True $ putStrLn "True"
unless False $ putStrLn "False"