| Safe Haskell | Safe-Inferred |
|---|
Lessons.Lesson11
Description
Notes taken by Julija Mikeliūnaitė
Synopsis
- foo :: Integer
- c :: Exception e => IO (Either e Integer)
- eager :: [Integer]
- lazy :: [Integer]
- lazy' :: Int
- lazy'' :: [Integer]
- first :: Int -> [Integer]
- data Expr
- prog1 :: Expr
- eval :: Expr -> Integer
- print' :: Expr -> String
- class Expression repr where
- class ExpressionMul repr where
- mul :: repr -> repr -> repr
- prog2 :: Integer
- prog3 :: String
- data GExpr a where
- evalG :: GExpr a -> a
Documentation
Haskell has exceptions. The error function is the simplest way to throw exceptions. error is a pure function and can be any type. Here, the error function works as an integer, therefore it can be returned.
c :: Exception e => IO (Either e Integer) Source #
For exception cathcing you need the Control.Exception package. The try function needs an IO block.
If the code is multithreaded, you can send exceptions to any thread.
Haskell is considered a lazy programming language. In a lazy language computations are only made if absolutely necessary.
If one of the items in the list is an error, the final result will be the error. This is an example of a strict/eager function.
>>>eageroj
The take x function takes the first x elements from the list and returns them. This is an example of a lazy function.
>>>lazy[1,2]
length is also a lazy function, because it counts how many items are in a list but does not care about their type (even if some of them may be errors).
>>>lazy'1
With take 1, if the first element is an error, then the result is the error.
>>>lazy''ooops
first :: Int -> [Integer] Source #
Even though the integer list is infinite, first 10 works fine, because of the laziness. If you were to print out the whole list [1..], it would just keep going forever to infinity.
>>>first 10[1,2,3,4,5,6,7,8,9,10]
Lists are constructed using :, therefore the first n elements can be checked one by one.
Eager calculations - trying to compute all data at once and store everything in memory. It can be achieved using libraries with the keyword Strict.
seq function:
seq :: a -> b -> b Simplest explanation: the return value is bottom if a is bottom, otherwise it is b.
Returns 5 and ensures that everything was calculated/checked.
>>>seq 4 55
Returns 5, because seq removes the top layer of what is uncalculated.
>>>seq [error "Aj"] 55
Does all of the calculations, no matter the layer.
>>>deepseq ([error "Aj"]:: [Int]) 5Aj
DSL - domain specific language. In our DSL's we had differend commands - a dictionary of tasks which we can use within our language. A classic example - calculator.
Expr (expression) can be either a literal (number) or an operation for two expressions (add, mul) or an operation for one expression (neg). This is already a DSL and now we can write programs using it.
eval :: Expr -> Integer Source #
This is used to define how the program should act with different expressions.
Evaluate >>> eval prog1 -15
print' :: Expr -> String Source #
This is used for printing different expressions to the console.
>>>print' prog1"-(5 + 4 + 6)"
class Expression repr where Source #
If the grammar is not initial, it's either final or tagless final. Tagless - because it doesnt have tags (like lit, add and so on). FInal - because it is the final function. Classes are used to achieve this. Classes define what we can do with something and not how to construct a value. For example, the lit function takes an integer and returns its representation.
Instances
| Expression String Source # | You don't need to cover every instance for printing, it all depends on what you need for your project/business. lit = show, because lit a = show a is redundant since they both have the same signature. |
| Expression Integer Source # | The interpretor for the grammar. |
class ExpressionMul repr where Source #
A new class is used to add multiplication.
Instances
| ExpressionMul Integer Source # | |
Defined in Lessons.Lesson11 | |
Recreating prog1, just without negation; later we add multiplication.
>>>prog290
This solves the issue with types by using multiple constructors.
evalG :: GExpr a -> a Source #
You can't add GItn and GBool since they are of different types.
>>>evalG (GInt 5)5>>>evalG (GAdd (GInt 5) (GInt 6))11>>>evalG (GEq (GInt 5) (GInt 6))False>>>evalG (GAdd (GInt 5) (GBool False))Couldn't match type `Bool' with `Integer' Expected: GExpr Integer Actual: GExpr Bool In the second argument of `GAdd', namely `(GBool False)' In the first argument of `evalG', namely `(GAdd (GInt 5) (GBool False))' In the expression: evalG (GAdd (GInt 5) (GBool False))