Eine funktionale Programmiersprache
filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter pred (x:xs)
| pred x = x : filter pred xs
| otherwise = filter pred xs
String, Int, LT, Num
fun x = x * x
sort :: Ord a => [a] -> [a]
--
"{- -}
"{- Kommentar-Block {- innerer Block -} wieder äußerer Block -}
"let c = 'a' -- Typ Char
let s = "abc" -- Typ String, bzw. [Char]
let i = 0 -- Typ Int
let i = 0 :: Integer -- Typ Integer
let d = 0.0 -- Typ Double
let d = 0 :: Double -- Typ Double
let b = True -- Typ Bool, Gegenteil: False
let l = [1,2,3,4] -- Typ [Int]
let l = [1..10] -- Kurzform einer Liste
let infinite = [1..] -- unendliche Liste (lazy)
let t = (1,"abc") -- Typ (Int, String)
let newList = newElement : list
let new List = list ++ [newElement]
filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter pred (x:xs)
| pred x = x : filter pred xs
| otherwise = filter pred xs
data Day =
Monday
| Tuesdays
| Wednesdays
| Thursday
| Friday
| Saturday
| Sunday
data Person =
Person String Int
type Name = String
type Age = Int
data Person = Person Name Age
let person = Person "SDK" 30
Wie kommen wir an die Eigenschaften heran?
getName (Person n _) = n
getAge (Person _ a) = a
Geht das noch besser/einfacher?
data Person = Person
{ name :: String
, age :: Int
}
let p = Person "SDK" 30
let p = Person
{ name = "SDK"
, age = 30
}
Accessoren:
name :: Person -> Name
age :: Person -> Age
Vorteile:
let newPerson =
p { name = "Flo" }
Nachteil:
data Person =
Person
{ name :: Name
, age :: Age
}
data Dog =
Dog
{ name :: Name
, age :: Age
}
Lösung:
"OverloadedRecordFields" (Language-Extension)
-- wird vom Compiler in Int umgewandelt
newtype Natural = MkNatural Int
Datentypen sind lazy per default, können aber mit dem strictness-flag ("!
") als non-lazy bzw. strict deklariert werden. Beispiel:
data RealFloat a => Complex a = !a :+ !a
Strictness in Funktionen mit "seq
" oder "!$
".
a
" muss eine Instanz der Typ-Klasse "Ord
" sein (muss also sortierbar sein)fun :: a -> b
compare :: Ord a => a -> a -> Ordering
Klassische Funktionen:
mult (a,b) = a*b
Haskell-Funktionen:
mult a b = a*b
multBy2 = mult 2
-- oder:
multBy2 = (*2)
Currying:
Lambda-Ausdrücke:
mult = \a b -> a*b
map2 = map (\a -> a * 2)
-- kürzer:
map2 = map (*2)
List-Concatanation:
infixr 5 ++
(++) :: [a] -> [a] -> [a]
(++) [] ys = ys
(++) (x:xs) ys = x : xs ++ ys
Function Composition:
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)
let a = (+) 2 3
let a = 2 `mult` 3
infix[l/r] n operator
Beispiel:
infixl 7 *
infixl 6 +, -
infixr 0 $
contrived :: ([a], Char, (Int, Float), String, Bool) -> Bool
contrived ([], 'b', (1, 2.0), "hi", True) = False
As-Pattern:
f (x:xs) = x:x:xs
-- geht kürzer
f s@(x:xs) = x:s -- s == x:xs
fib@(1:tfib) = 1 : 1 : [ a+b | (a,b) <- zip fib tfib ]
Wild-Cards:
head (x:_) = x
tail (_:xs) = xs
sign x | x > 0 = 1
| x == 0 = 0
| x < 0 = -1
let s = "1"
let default n = 0
let n = case reads s of
[(n,_)] -> n
_ -> 0
checkPrefix s con action next =
let (pre, post) = T.splitAt (T.length s) con
in if pre == s then action post else next
f x y | y > z = ...
| y == z = ...
| y < z = ...
where z = x*x
derive (Eq, Read, Show)
getChar :: IO Char
readFile :: FilePath -> IO Char
-- type FilePath = String
putChar :: Char -> IO () -- () ~= void
putStrLn :: String -> IO ()
writeFile :: FilePath -> String -> IO ()
Von IO:
Nach IO:
main :: IO ()
main = do
c <- getChar
if c == 'y'
then return ()
else main
public static void main( String[] args )
Vgl:
IO
im Rückgabewert sind IO
-Actionsdo
-Notation kann angewandt werdenIO
-Actions enthaltenDebug.Trace
do { a <- f ; m } ≡ f >>= \a -> do { m }
do { f ; m } ≡ f >> do { m }
do { m } ≡ m
do {
a <- f ;
b <- g ;
c <- h ;
return (a, b, c)
}
f >>= \a ->
g >>= \b ->
h >>= \c ->
return (a, b, c)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(>>) :: Monad m => m a -> m b -> m b
putStr :: String -> IO ()
putStr = mapM_ putChar
putStr' = foldr ((>>) . putChar) (return ())
putStrLn' s = putStr s >> putChar '\n'