하스켈 프로그래밍 입문 4
TRANSCRIPT
Applicative Functor
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Functor vs Applicative Functor
> fmap (+1) [1,2,3]
[2,3,4]
> pure (+) <*> [1,2,3] <*> [4,5,6]
[5,6,7,6,7,8,7,8,9]
Applicative Maybe 정의instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
(Just f) <*> x = fmap f x
Applicative Maybe 예제> Just (+3) <*> Just 4
Just 7
> pure (+3) <*> Nothing
Nothing
> pure (+) <*> Just 3 <*> Just 4
Just 7
> (*) <$> Just 2 <*> Just 8
Just 16
Applicative [] 예제> (*) <$> [1,2,3] <*> [1,0,0,1]
[1,0,0,1,2,0,0,2,3,0,0,3]
> pure 7
7
> pure 7 :: [Int]
[7]
Applicative IO 의 정의instance Applicative IO where
pure = return
a <*> b = do f <- a
x <- b
return (f x)
liftA2• 일반 함수를 두 개의 functor 에 쉽게 apply 할 수 있게 해주는 함수liftA2 :: (Applicative f) =>
(a -> b -> c) ->
f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
Applicative Functor 법칙1. pure f <*> x = fmap f x
2. pure id <*> v = v
3. pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
4. pure f <*> pure x = pure (f x)
5. u <*> pure y = pure ($ y) <*> u
mconcat• foldr f z [a, b, c]
• a `f` (b `f` (c `f` z))
• f = (<>), z = mempty
• a <> (b <> (c <> mempty))
mconcat :: Monoid m => [m] -> m
mconcat = foldr mappend mempty
foldMap• mconcat 에서 Monoid 인스턴스 제약을 제거
foldMap :: Monoid m => (a -> m) -> [a] -> m
foldMap g = mconcat . fmap g
foldr 다시 보기• foldr :: (a -> (b -> b)) -> b -> [a] -> b
• b -> b 는 composition 에 대해 Monoid• mappend = (.)• mempty = id
newtype Endo b = Endo { appEndo :: b -> b }
instance Monoid Endo where
mempty = Endo id
Endo g `mappend` Endo f = Endo (g . f)
foldComposingfoldComposing :: (a -> (b -> b)) -> [a] -> Endo b
foldComposing f = foldMap (Endo . f)
foldr :: (a -> (b -> b)) -> b -> [a] -> b
foldr f z xs = appEndo (foldComposing f xs) z
• foldr 을 foldMap 을 이용해 정의할 수 있다는 의미
foldComposing 연산1. foldComposing (+) [1, 2, 3]
2. foldMap (Endo . (+)) [1, 2, 3]
3. mconcat (fmap (Endo . (+)) [1, 2, 3])
4. mconcat (fmap Endo [(+1), (+2), (+3)])
5. mconcat [Endo (+1), Endo (+2), Endo (+3)]
6. Endo ((+1) . (+2) . (+3))
7. Endo (+6)
Foldable 타입 클래스class Foldable t where
foldMap :: Monoid m => (a -> m) -> t a -> m
foldr :: (a -> b -> b) -> b -> t a -> b
• foldMap 과 foldr 둘 중 하나만 정의하면 됨
Foldable 타입 클래스 함수• fold :: Monoid m => t m ->
m -- generalised mconcat
• foldr' :: (a -> b -> b) -> b -> t a -> b
• foldl :: (b -> a -> b) -> b -> t a -> b
• foldl' :: (b -> a -> b) -> b -> t a -> b
• foldr1 :: (a -> a -> a) -> t a -> a
• foldl1 :: (a -> a -> a) -> t a -> a
• toList :: t a -> [a]• null :: t a -> Bool• length :: t a -> Int• elem :: Eq a => a -> t a ->
Bool• maximum :: Ord a => t a -> a• minimum :: Ord a => t a -> a• sum :: Num a => t a -> a• product :: Num a => t a -> a
Data.Foldable 함수• traverse_ :: (Foldable t, Applicative f) => (a -> f
b) -> t a -> f ()
• Map each element of a structure to an action, evaluate these actions from left to right, and ignore the results. For a version that doesn't ignore the results see traverse.
• mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
• Map each element of a structure to a monadic action, evaluate these actions from left to right, and ignore the results. For a version that doesn't ignore the results see mapM.
Foldable 예제> import qualified Data.Map as M
> let testMap = M.fromList $ zip [0..] ["Yesterday","I","woke","up","sucking","a","lemon"]
> length testMap
7
> sum . fmap length $ testMap
29
> elem "lemon" testMap
True
> foldr1 (\x y -> x ++ (' ' : y)) testMap
"Yesterday I woke up sucking a lemon"
Traversable
deleteIfNegative :: (Num a, Ord a) => a -> Maybe a
deleteIfNegative x = if x < 0 then Nothing else Just x
rejectWithNegatives :: (Num a, Ord a) => [a] -> Maybe [a]
• deleteIfNegative 를 이용해서 rejectWithNegatives 를 구현하려면 ?
> let testList = [-5,3,2,-1,0]
> fmap deleteIfNegative testList
[Nothing,Just 3,Just 2,Nothing,Just 0]
No!!
Traversable 타입 클래스class (Functor t, Foldable t) => Traversable t where
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
sequenceA :: Applicative f => t (f a) -> f (t a)
-- These methods have default definitions.
-- They are merely specialised versions of the other two.
mapM :: Monad m => (a -> m b) -> t a -> m (t b)
sequence :: Monad m => t (m a) -> m (t a)
Traversable [] 정의instance Traversable [] where
-- sequenceA :: Applicative f => [f a] -> f [a]
sequenceA [] = pure []
sequenceA (u:us) = (:) <$> u <*> sequenceA us
// or
instance Traversable [] where
sequenceA us =
foldr (\u v -> (:) <$> u <*> v) (pure []) us
Foldable vs Traversable
• Foldable
• Monoid 콘텍스트• fold
• foldMap
• Traversable
• Applicative 콘텍스트• sequenceA
• traverse
Traversable 예제> let rejectWithNegatives = sequenceA . fmap deleteIfNegative
> :t rejectWithNegatives
rejectWithNegatives
:: (Num a, Ord a, Traversable t) => t a -> Maybe (t a)
> rejectWithNegatives testList
Nothing
> rejectWithNegatives [0..10]
Just [0,1,2,3,4,5,6,7,8,9,10]
traverse 를 이용한 Traversable [] 정의
instance Traversable [] where
traverse _ [] = pure []
traverse f (x:xs) = (:) <$> f x <*> traverse f xs
-- Or, equivalently:
instance Traversable [] where
traverse f xs =
foldr (\x v -> (:) <$> f x <*> v) (pure []) xs
traverse 와 sequenceA
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse f xs = sequenceA $ fmap f xs
sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
sequenceA xs = traverse id xs
Foldable/Traversable
출처 : https://wiki.haskell.org/Foldable_and_Traversable
참고 자료1. CS252 – Advanced Programming Language
Principles Applicative Functors
• http://cs.sjsu.edu/~austin/cs252-fall14/slides/CS252-Day09-ApplicativeFunctors.pdf
2. Haskell/Foldable
• https://en.wikibooks.org/wiki/Haskell/Foldable
3. Haskell/Traversable
• https://en.wikibooks.org/wiki/Haskell/Traversable