ITSTUD  
 
 
 
Programming Paradigms - Informationsteknik
WikIt / ProgrammingParadigms
ProgrammingParadigms

Övningar

ObjectOrientationExercises

ConcurrencyOrientedProgrammingExercises

LogicOrientedExercises

Tentasvar

ProgrammingParadigmsDecemberNollSju

ProgrammingParadigmsMarsNollÅtta

ProgrammingParadigmsAugustiNollÅtta

Links

Haskell + ghc tutorial

http://book.realworldhaskell.org/read/types-and-functions.html

1. lambda-calculus

1.1 Some easy Haskell functions

L = lambda
inc (Lx. x + 1)
twice (Lf. Lx. f x)
-- arg1: an integer
inc = \ x -> x + 1

-- arg1: a function
-- arg2: an integer
twice = \ f -> \ x -> f (f x)

1c)

(Lx. x)(Lx. x) = > (Lx. (Lx. x)) = > (Lx. x) => x

2a)

(Lf. Lx. x)

2b)

(Lf. Lx. f x)

2c)

type Church a = (a -> a) -> a -> a
church :: Integer -> Church a
church 0 = \ f -> \ x -> x
church n = \ f -> \ x -> f ( church(n - 1) f x)

unchurch :: Church Integer -> Integer
unchurch n = n (\ x -> x + 1) 0

2. Lecture 2008-10-31: His crazy live example (not tested)

head [1,2,3] -- Takes first part of list
tail [1,2,3]


--cons
a: [2,3] -- Gives [1,2,3]

[1,2] ++ [3,4] -- [1,2,3,4]

-- Range
[1..10] -- List 1 to 10
[1..] -- Infinite


take 10 [1..] -- Take first 10 elements in infinite litst

-- Strings
"Hello" -- List of chars
head "hello" -- Gives 'h'

"hello " ++ "world" -- Appents two lists of chars

[ i*i | i <- [1..10] ] -- Iterate over list, take element i, square it

-- Define function

----------------------------------------
module Lecture where

-- read | as where
squares n = [i*i | i <- [1..n]]
         -- {i*i | i <- {1..n}}   (Math representation)

-- :l Lecture
-- squares 4

----------------------------------------

-- (i,j) is pair/tuple
[(i,j) | i <- [1..10], j <- [1..i]] -- Loop j is nested in loop with i

[i | i <- [1..24], 24  `rem` i == 0] -- ´rem´ call rem function with args 24 and i
-- List of divisors to 24

----------------------------------------
factors n = [i | i <- [1..n-1], n `rem` i == 0]
prime n = factors n == [1]

[p \ p <- [1..100], prime p]


--- QuickSort
qsort (x:xs) = 
  qsort [y | <-  xs, y < x] ++ [x] ++
  qsort [y | <- xs, y >= x]

qsort [] = []
----------------------------------------

qsort [10, 9..1]
qsort "hello world"
qsort (words "I need a sentance, what shal i use")



-- Add numbers 1 to 10
foldl (+) 0 [1..10]
foldl (*) 1 [1..10]

foldl (&&) True [True, False, True]
foldl (++) [] (words "hello clounds hello sky")

----------------------------------------
plus x y =  "(" ++x++"+"++y++")"
----------------------------------------

plus "12" "13"

"12" `plus` "13"
"12" `plus` "13" `plus` "14"

-- We can see what foldl does...
foldl plus "z" ["a", "b", "c", "d"]


-- Does stuff the other way...
foldr plus "z" ["a", "b", "c", "d"]


-- Multiply by 10, add digit, repeat
foldl (\ x y ->10*x+y) 0 [1, 3, 4, 2]

----------------------------------------
import Char
digitVal d = ord d - ord '0'

-- Convert from char to int
numVal s = foldl (\ x y -> 10*x+y) 0 [digitVal c | c <- s ]
----------------------------------------
numVal "132" -- Gives 132


----------------------------------------
-- :l Calc
calc "123"
calc "1+2"
calc "1+(2*3)"

----------------------------------------
-- Input : String, Result: digit
-- Extracts digit from string
digit (x:xs) = 
  if isDigit x
  then [x]
  else []

----------------------------------------
digit "123"
-- "1"

digit "abc"
-- ""

----------------------------------------
-- Same as first def
digit (x:xs) = [x | isDigit x]
letter (x:xs) = [x | isAlpha x]
----------------------------------------

letter "123"
-- ""

----------------------------------------
digitOrLetter s = digit s  ++ letter s
----------------------------------------

digitOrLetter "asd"
-- "a"
digitOrLetter "123"
-- "1"


----------------------------------------
-- Defines new operator '|||', looks for stuff in p and q
p ||| q = \s -> p s ++ q s

-- Refactor code above:
digitOrLetter s = (digit ||| letter) s -- constructs function in place..

-- Simplify: 
digitOrLetter = digit ||| letter

-- Simplify old stuff:
satisfy p (x:xs) = [x | p x]

--Refactor:
digit = satisfy isDigit
letter = satisfy isAlpha
----------------------------------------

-- Constructs functions in intepreter
(satisfy isDigit | satisfy isAlpha) "123"

(satisfy isDigit | satisfy isAlphaNum) "123"
-- "11"

digit ""
-- Program error...

----------------------------------------
satisfy p (x:xs) = [x | p x]
satisfy p []     = []
----------------------------------------

-- Satisfy function that checks args == plus
satisfy (=='+') "+123"
-- "+"

----------------------------------------
exactly c = satisfy (==c)

satisfy p (x:xs) = [(x,xs) | p x]
satisfy p []     = []

-- s' is variable name, prime ok.
digitThenPlus s = 
  [((d, '+'), s'') | (d,s') <- digit s, 
                     ('+', s'') <- exactly '+' s']
----------------------------------------

digitThenPlus "1+2"
-- [(('1', '+'), "2")]

digitThenPlus "a+2"
'' []



----------------------------------------
p ... q = \s -> 
  [((x, y), s'') | (x,s') <- p s, (y,s'') <- q s']

digitThenPlus = digit ... exactly '+'
----------------------------------------


----------------------------------------
-- Wtf....
p @@ q = \s -> 
  [(x y,s'') | (x,s') <- p s, (y,s'') <- q s']

value x s = [(x,s)]
----------------------------------------

(value digitVal @@ digit) "132"
-- [(1,"32")]

----------------------------------------
digits = value (:) @@ digit @@ digits
     ||| value []
----------------------------------------

digits "123x"
-- "It works..."


----------------------------------------
-- "Hey that sounds useful, lets refactor my code"
many p = some p ||| value []
some p = value (:) @@ p @@ many p

digits = some digit
number = value numVal @@ some digit
----------------------------------------

number "123x"

----------------------------------------
numPlusNum = 
  value addition @@ number @@ exactly '+'  @@ number

addition x '+' y = x+y
----------------------------------------

numPlusNum "1+2"


----------------------------------------
infixl 6 @@, ##
infixl 5 |||

numPlusNum = 
  value (+) @@ number ## exactly '+' @@ number

p ## q = value (\x y->x) @@ p @@ q
----------------------------------------

numPlusNum "1+2"

----------------------------------------
expr = value (+) @@ term ## exactly '+' @@ term
  ||| term

term = value (+) @@ factor ## exactly '+' @@ factor
  ||| factor

factor = 
 ||| value id ## exactly '(' @@ expr ## exactly ')'

parse p s = 
  [x | (x, "") <- p s]
----------------------------------------

expr "1+2*3"
parse expr "1+2*3"

3. Lecture 2008-11-06: More haskell

-- haskell requires the elements of a list to have the same type
[1, 2.0]
-- [1.0, 2.0]

-- information about (+)
:i +

-- a as input has to be a Numeric type
-- a can be any type, Integer, Float etc.

-- information about Num
:i Num

-- Num is a class
-- Num depends on two other classes
-- any type in class Num has to provide support for all the operators listed here
-- instances of Num: Int, Integer, Float, Double etc.

-- test the sort function
:l List
sort [1,4,3,2,5]
-- [1,2,3,4,5]

-- so, we can sit here and test functions manually,
 but what we would like to is to automate this.

	module Lecture where
	import List
	
	-- function to test wheter or not a list is ordered
	ordered (x:y:xs) = x <= y && ordered (y:xs)
	ordered _ = True -- true if 0 or 1 element
	
ordered (sort [1,4,2,3])
-- True

	prop_sort xs = ordered (sort xs)

prop_sort [1,3,5,4]
-- True

	import Test.QuickCheck
	
	prop_sort (xs::[Integer]) = ordered (sort xs)
	-- the reason of putting [Integer] here is to tell quickCheck
what type of elements to test
	
quickCheck prop_sort
-- OK, passed 100 tests.
-- what happened was that quickCheck created 100 randomly generated test cases,
and they all passed
-- a random test case technique has become very popular,
it's quick to create them (it creates them itself)
	
	prop_insert (x::Integer) xs = ordered (insert x xs)
	
quickCheck prop_insert
-- Falsifiable, after 5 tests:
-- -1
-- [0, -1]
-- hmm, why this?! let's try it manually:

insert (-1) [0, -1]
-- [-1, 0, -1]
-- ok, well our definition of prop_insert is wrong

	prop_insert (x::Integer) xs = ordered xs ==> ordered (insert x xs)
	-- ==> means what?
	-- it's a conditional property to in this case check if the list is ordered

-- now, quickCheck will pass 100 tests.
-- quickCheck can also collect stats from testing

	prop_insert (x::Integer) xs =
		collect (length xs) $
		ordered xs ==> ordered (insert x xs)	
	
quickCheck prop_insert
-- 49% 0. (empty lists)
-- 32% 1. (one element)
-- 9% 2.
-- 8% 3.
-- 2% 4.
-- this feels like wrong balance
-- why did we test empty lists and 1-element lists so much?
because they always pass the precondition
-- the chance for longer lists to already be ordered is pretty low,
that's why we threw away so many of them

	orderedList :: (Ord a, Arbitrary a) => Gen [a]
	orderedList =
		do xs <- arbitrary
			return (sort xs)
			
	prop_insert2 x =
		forAll orderedList
			(\xs -> prop_insert x xs)
			
quickCheck prop_insert2
-- now we get a much more variety in the length of the test lists
-- why?
-- but ok, why do we actually use the sort function within prop_insert?
-- let's write another version that doesn't use sort()

	orderedNumList :: (Num a, Ord a, Arbitrary a) => Gen [a]
	orderedNumList =
		do x <- arbitrary
			listFrom x
	
	listFrom x =
		frequency [(1, return []),
				(5, do diff <- arbitrary
					xs <- listFrom (x+abs diff)
					return (x:xs))]

	prop_insert3 x =
		forAll orderedNumList $ \xs ->
			prop_insert x xs
			
quickCheck prop_insert3


-- now we're gonna do something called PROPERTY DRIVEN TESTING (using quickCheck)
-- we're gonna implement functionality for a queue

	instance QueueCLass Queue where
		empty = []
		add x xs = xs ++ [x]
		del (x:xs) = xs
		front (x:xs) = Just x
		front [] = Nothing 

-- he's not gonna test it because he's not satisfied
-- ++ is a damn slow operation, and he wants something better
-- any ideas why keeping the slow code? it's testable, we use it to test the real code
-- we can split the queue into two parts, ehrm...
-- he's gonna do it like a zig-zag airport queue

	data Queue a = Q [a] [a]
		deriving (Eq, Show)
		
	instance QueueClass [] where
		empty = Q [] []
		add x (Q front back) = Q front (x:back)
		-- he's storing the back in reverse order, so when we add we can put it
at the front of the list, which is gonna be fast
		-- when we delete, we take it from the front, an
		del (Q (x:front) back) = flipQ (Q front back)
		front (Q (x:front) back) = Just x
		front (Q [] back) = Nothing
	
	flipQ (Q [] back) = Q (reverse back) []
	flipQ (Q front back) = Q front back
	
-- but now we have the same name of the functions and haskell won't let me have that,
let's introduce a class and add "instance" to the above blocks

	class QueueClass q where
		empty :: q a
		add :: a -> q a -> q a
		del :: q a -> q a
		front :: q a -> Maybe a
		
	model (Q front back) = front ++ reverse back
	
-- now we want to test this code
	
	prop_empty = model empty == empty &&
		invariant (empty)
	
	-- these two empty's mean two different things because we used the model
function to convert between the first type of queue and the more efficient one

quickCheck prop_empty
-- OK, passed 100 tests.

	prop_add x (q::Queue Integer) =
		model (add x q) == add x (model q)

quickCheck prop_add
-- error, let's have a break
-- ok, we needed this:

	instance Arbitrary a => Arbitrary (Queue a) where
		arbitrary =
			do front <- arbitrary
			   back <- arbitrary
			   	return (Q front back)
			   	
-- now prop_add works!

	prop_front (q:: Queue Integer) =
		front q == front (model q)

-- testing of prop_front fails
-- because there was an invariant in our implementation
(add invariant-stuff to all the prop_x's?)

	invariant (Q frot back) =
		not (null front) || null back
		
	prop_add x (q::Queue Integer) =
		invariant q ==>
			model (add x q) == add x (model q) &&
				invariant (add x q)

-- yes, now the front is working 

	prop_del x (q::Queue Integer) =
		invariant q && q\=empty ==>
			model (del q) == del (model q) &&
				invariant (add x q)
Ändra denna sida | Visa ändringshistorik
Senast ändrad 2008-12-11 16:37:24
 
  Disclaimer