Difference between revisions of "Haskell"
m (Link to Haskell website.) |
(→Packages) |
||
(17 intermediate revisions by the same user not shown) | |||
Line 21: | Line 21: | ||
And then you can run via the executable file '''./hello'''. | And then you can run via the executable file '''./hello'''. | ||
+ | |||
+ | == Types == | ||
+ | Haskell allows you to define types but this is optional if no type is declared it will infer the type. Types in Haskell must start with a capital letter. | ||
+ | <source lang="Haskell"> | ||
+ | 5 -- Infers the type | ||
+ | 5 :: Double -- Define the type. | ||
+ | |||
+ | -- Ask ghci what type '5' is. | ||
+ | :t 5 | ||
+ | </source> | ||
+ | |||
+ | The unit type '''()''' is a type that has only one value '''()''' which is similar to '''void''' in other languages. | ||
+ | |||
+ | You can combine types easily in one of two ways: ''Tuples'' and ''Lists''. Lists hold many values of the same type whereas Tuples can hold values of different types. | ||
+ | <source lang="Haskell"> | ||
+ | [1, 2, 3] -- Simple list with the values 1 to 3. | ||
+ | [1 .. 5] -- List with the values 1 to 5 | ||
+ | [1, 3 .. 10] -- List of odd values between 1 and 10. | ||
+ | ['H', 'e', 'l', 'l', 'o'] -- A String! | ||
+ | |||
+ | (1, true) -- Simple Tuple. | ||
+ | (1, True, 2.0, 2) -- A longer Tuple | ||
+ | |||
+ | zip [1 .. 5] ['a' .. 'e'] -- Combine the two lists into a list of tuples: [(1, 'a'), (2, 'b') ...] | ||
+ | map (+ 2) [1 .. 5] -- Map function on a list: [3,4,5,6,7] | ||
+ | filter (> 2) [1 .. 5] -- Filter function on a list: [3,4,5] | ||
+ | fst (1, 2) -- Get the first element of the Tuple. | ||
+ | snd (1, 2) -- Get the second element of the Tuple. | ||
+ | map fst [(1, 2), (3, 4), (5, 6)] -- Apply the first function to each tuple in the list: [1,3,5]. | ||
+ | </source> | ||
+ | |||
+ | == Functions == | ||
+ | <source lang="Haskell"> | ||
+ | inc x = x+1 -- Define an increment function. | ||
+ | add x y = x + y -- Define an addition function that takes two parameters. | ||
+ | (\x -> \y -> x+y) 1 2 -- Lambda version of add taking 1 & 2 as it's parameters. | ||
+ | </source> | ||
+ | You can also give types to your functions: | ||
+ | <source lang="Haskell"> | ||
+ | inc :: Int -> Int -- inc is a function that takes an Int and outputs an Int. | ||
+ | inc x = x+1 | ||
+ | |||
+ | add :: Int -> Int -> Int -- inc is a function that takes two Ints as parameters and outputs an Int. | ||
+ | add x y = x + y | ||
+ | |||
+ | -- Define the factorial function in parts using pattern matching. | ||
+ | fact :: Int -> Int | ||
+ | fact 0 = 1 | ||
+ | fact n = n * fact ( n - 1 ) | ||
+ | |||
+ | -- Define the factorial function using guards, guards are like piecewise functions in mathematics. | ||
+ | fact :: Integer -> Integer | ||
+ | fact n | n == 0 = 1 | ||
+ | | n /= 0 = n * fact (n-1) | ||
+ | |||
+ | -- You can split a complicated function into parts using 'where' | ||
+ | roots :: (Float, Float, Float) -> (Float, Float) | ||
+ | roots (a,b,c) = (x1, x2) where | ||
+ | x1 = e + sqrt d / (2 * a) | ||
+ | x2 = e - sqrt d / (2 * a) | ||
+ | d = b * b - 4 * a * c | ||
+ | e = - b / (2 * a) | ||
+ | |||
+ | -- Haskell allows you to do function composition with the '.' operator. | ||
+ | composedFunc = outer.inner -- outer and inner are functions. | ||
+ | -- composedFunc will compute the inner function then pass the return value to the outer function, compute that and return. | ||
+ | -- Note: the return value from inner needs to match that of the parameter value of outer. | ||
+ | </source> | ||
+ | |||
+ | |||
+ | In Haskell you can have conceptually infinite functions! | ||
+ | <source lang="Haskell"> | ||
+ | numsFrom n = n : numsFrom (n+1) -- A list of all numbers (n -> Infinity) from the argument. | ||
+ | squares = map (^2) (numsFrom 0) -- A list of all squares of the positive integers. | ||
+ | fib = 1 : 1 : [ a+b | (a,b) <- zip fib (tail fib) ] -- The list of all Fibonacci numbers! | ||
+ | </source> | ||
+ | |||
+ | Infinite functions are cool, but you will probably want to get a finite sample from them: | ||
+ | <source lang="Haskell"> | ||
+ | take 10 fib -- The first 10 Fibonacci numbers. | ||
+ | filter (< 100) (take 30 fib) -- All Fib numbers less than 100. | ||
+ | filter odd (filter (<300) (take 30 fib)) -- All odd Fib numbers less than 300. | ||
+ | </source> | ||
+ | |||
+ | == Parallel Programming == | ||
+ | You can write multi-threaded or parallel programs using the parallel library, you can install a library like so: | ||
+ | <source lang="bash"> | ||
+ | cabal install --lib parallel | ||
+ | </source> | ||
+ | |||
+ | <source lang="Haskell"> | ||
+ | import Control.Parallel | ||
+ | |||
+ | main = a `par` b `par` c `pseq` print (a + b + c) | ||
+ | where | ||
+ | a = ack 3 10 | ||
+ | b = fac 42 | ||
+ | c = fib 34 | ||
+ | |||
+ | fac 0 = 1 | ||
+ | fac n = n * fac (n-1) | ||
+ | |||
+ | ack 0 n = n+1 | ||
+ | ack m 0 = ack (m-1) 1 | ||
+ | ack m n = ack (m-1) (ack m (n-1)) | ||
+ | |||
+ | fib 0 = 0 | ||
+ | fib 1 = 1 | ||
+ | fib n = fib (n-1) + fib (n-2) | ||
+ | </source> | ||
+ | |||
+ | <source lang="bash"> | ||
+ | ./parallel -N3 # Use 3 cores. | ||
+ | </source> | ||
+ | |||
+ | == Modules == | ||
+ | You can split Haskell code with modules. Each module must be in a Haskell file with the same name: | ||
+ | |||
+ | '''Custom.hs''' | ||
+ | <source lang="Haskell"> | ||
+ | module Custom ( | ||
+ | showEven, | ||
+ | showBoolean | ||
+ | ) where | ||
+ | |||
+ | showEven:: Int-> Bool | ||
+ | showEven x = do | ||
+ | if x `rem` 2 == 0 | ||
+ | then True | ||
+ | else False | ||
+ | |||
+ | showBoolean :: Bool->Int | ||
+ | showBoolean c = do | ||
+ | if c == True | ||
+ | then 1 | ||
+ | else 0 | ||
+ | </source> | ||
+ | |||
+ | '''main.hs''' | ||
+ | <source lang="Haskell"> | ||
+ | import Custom | ||
+ | |||
+ | main = do | ||
+ | print(showEven 4) | ||
+ | print(showBoolean True) | ||
+ | </source> | ||
+ | |||
+ | == Custom Types == | ||
+ | === Data === | ||
+ | <source lang="Haskell"> | ||
+ | -- Create the custom data type Shape that extends Show (so that print will output something) | ||
+ | data Shape = Circle Float Float Float | ||
+ | | Rectangle Float Float Float Float | ||
+ | deriving (Show) | ||
+ | |||
+ | -- A function for calculating the surface area. | ||
+ | surface :: Shape -> Float | ||
+ | surface (Circle _ _ r) = pi * r ^ 2 | ||
+ | surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1) | ||
+ | |||
+ | -- Override properties such as the == operator | ||
+ | instance Eq Shape where | ||
+ | Circle _ _ r1 == Circle _ _ r2 = r1 == r2 | ||
+ | Rectangle x11 y11 x12 y12 == Rectangle x21 y21 x22 y22 = (abs $ x12 - x21) == (abs $ x22 - x21) && (abs $ y12 - y11) == (abs $ y22 - y21) | ||
+ | _ == _ = False | ||
+ | |||
+ | -- Another custom data type with a different format. | ||
+ | data Animal = Animal { | ||
+ | name :: String, | ||
+ | legCount :: Int, | ||
+ | height :: Float | ||
+ | } deriving (Show) | ||
+ | |||
+ | main = do | ||
+ | print (surface $ Circle 10 20 10) | ||
+ | print (Circle 10 20 10) | ||
+ | |||
+ | let cow = Animal "Cow" 4 1.6 | ||
+ | |||
+ | -- Here we can output a specific value of our type. | ||
+ | print (height cow) | ||
+ | </source> | ||
+ | |||
+ | === Type === | ||
+ | Types is a way to alias a name with another type. | ||
+ | <source lang="Haskell"> | ||
+ | -- Define PhoneNumber as the type String | ||
+ | type PhoneNumber = String | ||
+ | type Name = String | ||
+ | |||
+ | -- Define PhoneBook as the type of a list of tuples containing types Name and PhoneNumber | ||
+ | type PhoneBook = [(Name,PhoneNumber)] | ||
+ | |||
+ | -- Create a variable with type PhoneBook | ||
+ | phoneBook :: PhoneBook | ||
+ | phoneBook = | ||
+ | [ | ||
+ | ("name 1", "number 1"), | ||
+ | ("name 2", "number 2") | ||
+ | ] | ||
+ | </source> | ||
+ | |||
+ | == Packages == | ||
+ | [https://www.haskell.org/cabal/ Cabal] is a system for building and packaging Haskell libraries and programs. | ||
+ | |||
+ | |||
+ | Search for a package: | ||
+ | <source lang="bash"> | ||
+ | cabal list <PACKAGE NAME> | ||
+ | </source> | ||
+ | |||
+ | Install a package with Cabal: | ||
+ | <source lang="bash"> | ||
+ | cabal install --lib <PACKAGE NAME> | ||
+ | </source> | ||
== See Also == | == See Also == | ||
+ | * [http://www.newthinktank.com/2015/08/learn-haskell-one-video/ Haskell Cheat Sheet] | ||
* [https://wiki.haskell.org/Learn_Haskell_in_10_minutes Learn Haskell in 10 minutes.] | * [https://wiki.haskell.org/Learn_Haskell_in_10_minutes Learn Haskell in 10 minutes.] | ||
+ | * [https://www.haskell.org/tutorial/ Gentle Introduction To Haskell] | ||
+ | * [https://www.tutorialspoint.com/haskell/index.htm Tutorials Point Haskell] | ||
+ | * [https://github.com/tweag/asterius Haskell to web assembly compiler.] |
Latest revision as of 02:06, 17 March 2021
Haskell is a functional programming langauge used in Cardano.
Contents
Getting Started
Install the Haskell platform with:
sudo apt-get install haskell-platform
Then run the interpreter via:
ghci
Quitting the Haskell interpreter is the same as vim: :q or :quit.
You can write Haskell in .hs files then compile using ghc like so:
ghc -o hello hello.hs
And then you can run via the executable file ./hello.
Types
Haskell allows you to define types but this is optional if no type is declared it will infer the type. Types in Haskell must start with a capital letter.
5 -- Infers the type
5 :: Double -- Define the type.
-- Ask ghci what type '5' is.
:t 5
The unit type () is a type that has only one value () which is similar to void in other languages.
You can combine types easily in one of two ways: Tuples and Lists. Lists hold many values of the same type whereas Tuples can hold values of different types.
[1, 2, 3] -- Simple list with the values 1 to 3.
[1 .. 5] -- List with the values 1 to 5
[1, 3 .. 10] -- List of odd values between 1 and 10.
['H', 'e', 'l', 'l', 'o'] -- A String!
(1, true) -- Simple Tuple.
(1, True, 2.0, 2) -- A longer Tuple
zip [1 .. 5] ['a' .. 'e'] -- Combine the two lists into a list of tuples: [(1, 'a'), (2, 'b') ...]
map (+ 2) [1 .. 5] -- Map function on a list: [3,4,5,6,7]
filter (> 2) [1 .. 5] -- Filter function on a list: [3,4,5]
fst (1, 2) -- Get the first element of the Tuple.
snd (1, 2) -- Get the second element of the Tuple.
map fst [(1, 2), (3, 4), (5, 6)] -- Apply the first function to each tuple in the list: [1,3,5].
Functions
inc x = x+1 -- Define an increment function.
add x y = x + y -- Define an addition function that takes two parameters.
(\x -> \y -> x+y) 1 2 -- Lambda version of add taking 1 & 2 as it's parameters.
You can also give types to your functions:
inc :: Int -> Int -- inc is a function that takes an Int and outputs an Int.
inc x = x+1
add :: Int -> Int -> Int -- inc is a function that takes two Ints as parameters and outputs an Int.
add x y = x + y
-- Define the factorial function in parts using pattern matching.
fact :: Int -> Int
fact 0 = 1
fact n = n * fact ( n - 1 )
-- Define the factorial function using guards, guards are like piecewise functions in mathematics.
fact :: Integer -> Integer
fact n | n == 0 = 1
| n /= 0 = n * fact (n-1)
-- You can split a complicated function into parts using 'where'
roots :: (Float, Float, Float) -> (Float, Float)
roots (a,b,c) = (x1, x2) where
x1 = e + sqrt d / (2 * a)
x2 = e - sqrt d / (2 * a)
d = b * b - 4 * a * c
e = - b / (2 * a)
-- Haskell allows you to do function composition with the '.' operator.
composedFunc = outer.inner -- outer and inner are functions.
-- composedFunc will compute the inner function then pass the return value to the outer function, compute that and return.
-- Note: the return value from inner needs to match that of the parameter value of outer.
In Haskell you can have conceptually infinite functions!
numsFrom n = n : numsFrom (n+1) -- A list of all numbers (n -> Infinity) from the argument.
squares = map (^2) (numsFrom 0) -- A list of all squares of the positive integers.
fib = 1 : 1 : [ a+b | (a,b) <- zip fib (tail fib) ] -- The list of all Fibonacci numbers!
Infinite functions are cool, but you will probably want to get a finite sample from them:
take 10 fib -- The first 10 Fibonacci numbers.
filter (< 100) (take 30 fib) -- All Fib numbers less than 100.
filter odd (filter (<300) (take 30 fib)) -- All odd Fib numbers less than 300.
Parallel Programming
You can write multi-threaded or parallel programs using the parallel library, you can install a library like so:
cabal install --lib parallel
import Control.Parallel
main = a `par` b `par` c `pseq` print (a + b + c)
where
a = ack 3 10
b = fac 42
c = fib 34
fac 0 = 1
fac n = n * fac (n-1)
ack 0 n = n+1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) (ack m (n-1))
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
./parallel -N3 # Use 3 cores.
Modules
You can split Haskell code with modules. Each module must be in a Haskell file with the same name:
Custom.hs
module Custom (
showEven,
showBoolean
) where
showEven:: Int-> Bool
showEven x = do
if x `rem` 2 == 0
then True
else False
showBoolean :: Bool->Int
showBoolean c = do
if c == True
then 1
else 0
main.hs
import Custom
main = do
print(showEven 4)
print(showBoolean True)
Custom Types
Data
-- Create the custom data type Shape that extends Show (so that print will output something)
data Shape = Circle Float Float Float
| Rectangle Float Float Float Float
deriving (Show)
-- A function for calculating the surface area.
surface :: Shape -> Float
surface (Circle _ _ r) = pi * r ^ 2
surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)
-- Override properties such as the == operator
instance Eq Shape where
Circle _ _ r1 == Circle _ _ r2 = r1 == r2
Rectangle x11 y11 x12 y12 == Rectangle x21 y21 x22 y22 = (abs $ x12 - x21) == (abs $ x22 - x21) && (abs $ y12 - y11) == (abs $ y22 - y21)
_ == _ = False
-- Another custom data type with a different format.
data Animal = Animal {
name :: String,
legCount :: Int,
height :: Float
} deriving (Show)
main = do
print (surface $ Circle 10 20 10)
print (Circle 10 20 10)
let cow = Animal "Cow" 4 1.6
-- Here we can output a specific value of our type.
print (height cow)
Type
Types is a way to alias a name with another type.
-- Define PhoneNumber as the type String
type PhoneNumber = String
type Name = String
-- Define PhoneBook as the type of a list of tuples containing types Name and PhoneNumber
type PhoneBook = [(Name,PhoneNumber)]
-- Create a variable with type PhoneBook
phoneBook :: PhoneBook
phoneBook =
[
("name 1", "number 1"),
("name 2", "number 2")
]
Packages
Cabal is a system for building and packaging Haskell libraries and programs.
Search for a package:
cabal list <PACKAGE NAME>
Install a package with Cabal:
cabal install --lib <PACKAGE NAME>