module Aula13 where import Control.Applicative -- classes de tipo já vistas -- Functor, Num, Foldable, Integral -- Monoid, Eq, Show, Read -- Voltando a falar de functor -- data f a = .... -- por motivos didáticos instance Show (Integer -> Integer) where show _ = "funcao" soma = (+) :: Integer -> Integer -> Integer -- fmap de lista :: (a->b) -> [a] -> [b] -- aqui, para soma, temos a = Integer, b = Integer -> Integer -- fmap_soma :: [Integer] -> [Integer -> Integer] -- fmap_soma = fmap soma lista_de_args_esq = [1000, 2000, 3000] lista_de_args_dir = [7, 9, 13, 19, 51, 88, 91] naturais = [0..] funcs_encaixotadas = fmap soma lista_de_args_esq lista_de_resultados = funcs_encaixotadas <*> lista_de_args_dir data Lista a where Vazia :: Lista a (:#) :: a -> Lista a -> Lista a deriving Eq infixr :# instance Show a => Show (Lista a) where show :: Show a => Lista a -> String show s = showAux s True where showAux Vazia True = "{}" showAux Vazia False = "" showAux (cab :# Vazia) True = "{" ++ (show cab) ++ "}" showAux (cab :# Vazia) False = (show cab) ++ "}" showAux (cab :# corpo) True = "{" ++ (show cab) ++ ", " ++ (showAux corpo False) showAux (cab :# corpo) False = (show cab) ++ ", " ++ (showAux corpo False) instance Functor Lista where fmap _ Vazia = Vazia fmap fun (cab :# corpo) = (fun cab) :# (fmap fun corpo) concatena :: Lista a -> Lista a -> Lista a concatena x Vazia = x concatena Vazia x = x concatena (cab :# corpo) x = cab :# (concatena corpo x) instance Applicative Lista where pure x = x :# Vazia Vazia <*> _ = Vazia _ <*> Vazia = Vazia -- tecnicamente funciona mas não é o que queremos: -- (Junta fun_cab fun_corpo) <*> (Junta arg_cab arg_corpo) = Junta (fun_cab arg_cab) (fun_corpo <*> arg_corpo) (fun_cab :# fun_corpo) <*> lista_de_args = concatena (fun_cab <$> lista_de_args) (fun_corpo <*> lista_de_args) ex_fun :: Lista (Integer -> Integer) ex_fun = (+2) :# ((+4):# Vazia) ex_args :: Lista Integer ex_args = 100 :# 200 :# 300 :# 400 :# Vazia -- liftA2 -- liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c -- generaliza fmap para funções "binárias" -- como seria liftA3? liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d -- liftA3 fun x y z = (liftA2 fun x y) <*> z -- liftA3 = (((<*>) .) .) . liftA2 liftA3 = ((.) ((.) (<*>))) . liftA2 -- Como deve ser a definição de liftA2 usando <*>? meuLiftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c -- meuLiftA2 fun caixa_arg_a caixa_arg_b = (pure fun) <*> caixa_arg_a <*> caixa_arg_b -- pure fun :: f (a -> b -> c) -- caixa_arg1 :: f a -- (pure fun) <*> caixa_arg1 :: f (b -> c) meuLiftA2 fun caixa_arg_a caixa_arg_b = fun <$> caixa_arg_a <*> caixa_arg_b -- LEIS de Applicative -- fun <$> é o mesmo que (pure fun) <*> -- Como definir <*> usando liftA2 ? meuApply :: Applicative f => f (a->b) -> f a -> f b meuApply = liftA2 ($) -- bla = ble $ bli blo blu -- bla = ($) ble (bli blo blu) -- = ble (bli blo blu) --- DESVIO composta_binaria :: (c -> d) -> (a -> b -> c) -> a -> b -> d composta_binaria = (.) . (.) composta_ternaria = (.) . (.) . (.) -- Investigando aplicações de aplicativo data TalvezTurbinado a where Erro :: [String] -> TalvezTurbinado a OK :: a -> TalvezTurbinado a deriving (Show, Eq) instance Functor TalvezTurbinado where fmap :: (a -> b) -> TalvezTurbinado a -> TalvezTurbinado b fmap _ (Erro x) = Erro x fmap fun (OK val_a) = OK (fun val_a) instance Applicative TalvezTurbinado where pure :: a -> TalvezTurbinado a pure = OK (<*>) :: TalvezTurbinado (a -> b) -> TalvezTurbinado a -> TalvezTurbinado b (OK fun) <*> (OK arg) = OK (fun arg) (Erro lista_de_erros_da_fun) <*> (Erro lista_de_erros_do_arg) = Erro (lista_de_erros_da_fun ++ lista_de_erros_do_arg) (Erro lista_de_erros_da_fun) <*> _ = Erro lista_de_erros_da_fun _ <*> (Erro lista_de_erros_do_arg) = Erro lista_de_erros_do_arg