Difference between revisions of "Haskell"

From Organic Design wiki
(Created page with notes on how to get started with Haskell.)
 
(Packages)
 
(18 intermediate revisions by the same user not shown)
Line 1: Line 1:
Haskell is a functional programming langauge used in [[Cardano]].
+
[https://www.haskell.org/ Haskell] is a functional programming langauge used in [[Cardano]].
  
 
== Getting Started ==
 
== Getting Started ==
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.

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>

See Also