121 lines
3.8 KiB
Haskell
Executable File
121 lines
3.8 KiB
Haskell
Executable File
-- Partial application is awesome, since haskell functions are curried:
|
|
compareWithHundred :: (Num a, Ord a) => a -> Ordering
|
|
compareWithHundred x = compare 100 x
|
|
|
|
-- this is equivalent to:
|
|
compareWithHundred :: (Num a, Ord a) => a -> Ordering
|
|
compareWithHundred = compare 100
|
|
|
|
-- Infix functions can also be partially-applied:
|
|
divideByTen :: (Floating a) => a -> a
|
|
divideByTen = (/10)
|
|
|
|
-- (/10) 200 == 200 / 10
|
|
|
|
isUpperAlphanum :: Char -> Bool
|
|
isUpperAlphanum = (`elem` ['A'..'Z'])
|
|
|
|
-- Functions can take functions as params:
|
|
applyTwice :: (a -> a) -> a -> a
|
|
applyTwice f x = f (f x)
|
|
|
|
-- Example implementation of zipWith:
|
|
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
|
|
zipWith _ [] _ = []
|
|
zipWith _ _ [] = []
|
|
zipWith f (x:xs) (y:ys) = (f x y):(zipWith f xs ys)
|
|
|
|
flip :: (a -> b -> c) -> b -> a -> c
|
|
flip f x y = f y x
|
|
|
|
-- map built-in:
|
|
map (a -> b) -> [a] -> [b]
|
|
map _ [] = []
|
|
map f (x:xs) = (f x):(map f xs)
|
|
|
|
-- filter built-in:
|
|
filter (a -> Bool) -> [a] -> [a]
|
|
filter _ [] = []
|
|
filter f (x:xs)
|
|
| f x = x:(filter xs)
|
|
| otherwise = filter xs
|
|
|
|
-- Largest # under 100000 divisible by 3829:
|
|
-- (this stops after finding the first matching value, because of lazy evaluation)
|
|
largestDivisible :: (Integral a) => a
|
|
largestDivisible = head (filter p [100000,99999,..])
|
|
where p x = x `mod` 3829 == 0
|
|
|
|
takeWhile :: (a -> Bool) -> [a] -> [a]
|
|
takeWhile _ [] = []
|
|
takeWhile p (x:xs)
|
|
| p x = x:(takeWhile p xs)
|
|
| otherwise = []
|
|
|
|
-- Collatz sequence builder
|
|
chain :: (Integral a) => a -> [a]
|
|
chain 1 = [1]
|
|
chain n
|
|
| even n = n:(chain (n `div` 2))
|
|
| odd n = n:(chain (n*3 + 1))
|
|
|
|
numLongChains :: Int
|
|
numLongChains = length (filter isLong (map chain [1..100]))
|
|
where isLong xs = length xs > 15
|
|
|
|
-- Instead, with lambdas!
|
|
numLongChains :: Int
|
|
numLongChains = length (filter (\xs -> length xs > 15) (map chain [1..100]))
|
|
|
|
-- You can pattern-match in lambdas, but only on one case. If a value doesn't match the pattern,
|
|
-- you get a runtime error. So, make sure your pattern is exhaustive.
|
|
|
|
-- Folds - foldl - left fold
|
|
sum :: (Num a) => [a] -> a
|
|
sum xs = foldl (\acc x -> acc + x) 0 xs
|
|
|
|
-- Or, more succinctly with currying:
|
|
sum xs = foldl (+) 0 xs
|
|
|
|
-- Generally, because of currying, a function `foo a = bar b a` can be written as `foo = bar b`
|
|
-- Another fold example:
|
|
elem :: (Eq a) => a -> [a] -> Bool
|
|
elem y ys = foldl (\acc x -> if x == y then True else acc) False ys
|
|
|
|
-- Right folds `foldr` work similarly, but from the right side, and the acc x are reversed. e.g.
|
|
map :: (a -> b) -> [a] -> [b]
|
|
map f xs = foldr (\x acc -> (f x):acc) [] xs
|
|
|
|
-- We could have done this with `foldl` and `++`, but cons is much cheaper than `++`, so we generally
|
|
-- use `foldr` when building lists from lists.
|
|
|
|
-- `foldl1` and `foldr1` work the same as `foldl` and `foldr`, but they use the starting element in
|
|
-- the list as the initial accumulator (the left-most or right-most, respectively)
|
|
|
|
-- `scanl` and `scanr` are like their fold* counterparts, but return an array of all the states of the accumulator:
|
|
scanl1Test = scanl1 (\acc x -> if x > acc then x else acc) [3,4,5,3] -- == [3,4,5,5]
|
|
|
|
-- These have a `scanl1` and `scanr1` equivalent. The final result of `scanl*` is the last element, and the head
|
|
-- element for `scanr1`
|
|
|
|
-- Function application
|
|
-- Take:
|
|
($) :: (a -> b) -> a -> b
|
|
f $ x = f x
|
|
|
|
-- Right-associative function application!
|
|
sum (map sqrt (1 + 2 + 3)) == sum $ map $ sqrt $ 1 + 2 + 3
|
|
|
|
-- This also means we can use function application... as a function:
|
|
mapTest1 = map ($ 3) [(4+), (^2)] -- == [4 + 3, 3 ^ 2]
|
|
|
|
-- Also, function composition:
|
|
(.) :: (b -> c) -> (a -> b) -> a -> c
|
|
f . g = \x -> f (g x)
|
|
|
|
-- This means more concise code! TFAE
|
|
mapTest2 = map (\x -> negate $ abs x) [1..3]
|
|
mapTest3 = map (negate . abs) [1..3]
|
|
|
|
-- If we want to compose functions with multiple parameters, we need to partially apply them first.
|