--- linguagem: haskell tradutor/contribuidor: - ["Lucas Tonussi", "http://www.inf.ufsc.br/~tonussi/"] --- As linguagens funcionais são linguagens de programação com base em avaliação de funções matemáticas (expressões), evitando-se o conceito de mudança de estado com alteração de dados. Neste aspecto, este paradigma é oposto ao paradigma imperativo que se baseia em alterações de estados. A programação funcional começou no cálculo lambda, que foi base teórica para o desenvolvimento deste paradigma de programação. ```haskell -- Para comentar a linha basta dois traços seguidos. {- Abre chaves traço e traço fecha chaves cria um campo para comentário em múltiplas linhas. -} ---------------------------------------------------- -- 1. Tipos Primitivos de Dados e Operadores ---------------------------------------------------- -- Numerais 0 -- 3 1 -- 1 2 -- 2 ... -- Alguns Operadores Fundamentais 7 + 7 -- 7 mais 7 7 - 7 -- 7 menos 7 7 * 7 -- 7 vezes 7 7 / 7 -- 7 dividido por 7 -- Divisões não são inteiras, são fracionádas por padrão da linguagem 28736 / 82374 -- 0.3488479374559934 -- Divisão inteira 82374 `div` 28736 -- 2 -- Divisão modular 82374 `mod` 28736 -- 24902 -- Booleanos como tipo primitivo de dado True -- Verdadeiro False -- Falso -- Operadores unitário not True -- Nega uma verdade not False -- Nega uma falácia -- Operadores binários 7 == 7 -- 7 é igual a 7 ? 7 /= 7 -- 7 é diferente de 7 ? 7 < 7 -- 7 é menor que 7 ? 7 > 7 -- 7 é maior que 7 ? {- Haskell é uma linguagem que tem uma sintáxe bastante familiar na matemática, por exemplo em chamadas de funções você tem: NomeFunção ArgumentoA ArgumentoB ArgumentoC ... -} -- Strings e Caractéres "Texto entre abre áspas e fecha áspas define uma string" 'a' -- Caractere 'A' -- Caractere 'Strings entre aspas simples sobe um erro' -- Erro léxico! -- Concatenação de Strings "StringA" ++ "StringB" -- "StringAStringB" -- Você pode listar uma string pelos seus caractéres "AbBbbcAbbcbBbcbcb" !! 0 -- 'A' "AbBbbcAbbcbBbcbcb" !! 1 -- 'b' "AbBbbcAbbcbBbcbcb" !! 2 -- 'B' ---------------------------------------------------- -- Listas e Túplas ---------------------------------------------------- -- A construção de uma lista precisa ser de elementos homogêneos [1, 2, 3, 4, 5] -- Homogênea [1, a, 2, b, 3] -- Heterogênea (Erro) -- Haskell permite que você crie sequências [1..5] {- Haskell usa avaliação preguiçosa o que Permite você ter listas "infinitas" -} -- Uma lista "infinita" cuja razão é 1 [1..] -- O 777º elemento de uma lista de razão 1 [1..] !! 777 -- 778 -- União de listas [lista_0] ++ [lista_1] ++ [lista_i] [1..5] ++ [6..10] ++ [1..4] -- [1,2,3,4,5,6,7,8,9,10,1,2,3,4] -- Adiciona um cabeçalho a sua lista e desloca a cauda 0:[1..10] -- [0, 1, 2, 3, 4, 5] 'a':['a'..'e'] -- "aabcde" -- Indexação em uma lista [0..] !! 5 -- 5 -- Operadores de Listas usuais head ['a'..'e'] -- Qual o cabeçalho da lista ? tail ['a'..'e'] -- Qual a cauda da lista ? init ['a'..'e'] -- Qual a lista menos o último elemento ? last ['a'..'e'] -- Qual o último elemento ? -- list comprehensions [x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10] -- with a conditional [x*2 | x <- [1..5], x*2 > 4] -- [6, 8, 10] -- Every element in a tuple can be a different type, but a tuple has a -- fixed length. -- A tuple: ("haskell", 1) -- accessing elements of a tuple fst ("haskell", 1) -- "haskell" snd ("haskell", 1) -- 1 ---------------------------------------------------- -- 3. Functions ---------------------------------------------------- -- A simple function that takes two variables add a b = a + b -- Note that if you are using ghci (the Haskell interpreter) -- You'll need to use `let`, i.e. -- let add a b = a + b -- Using the function add 1 2 -- 3 -- You can also put the function name between the two arguments -- with backticks: 1 `add` 2 -- 3 -- You can also define functions that have no letters! This lets -- you define your own operators! Here's an operator that does -- integer division (//) a b = a `div` b 35 // 4 -- 8 -- Guards: an easy way to do branching in functions fib x | x < 2 = x | otherwise = fib (x - 1) + fib (x - 2) -- Pattern matching is similar. Here we have given three different -- definitions for fib. Haskell will automatically call the first -- function that matches the pattern of the value. fib 1 = 1 fib 2 = 2 fib x = fib (x - 1) + fib (x - 2) -- Pattern matching on tuples: foo (x, y) = (x + 1, y + 2) -- Pattern matching on lists. Here `x` is the first element -- in the list, and `xs` is the rest of the list. We can write -- our own map function: myMap func [] = [] myMap func (x:xs) = func x:(myMap func xs) -- Anonymous functions are created with a backslash followed by -- all the arguments. myMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7] -- using fold (called `inject` in some languages) with an anonymous -- function. foldl1 means fold left, and use the first value in the -- list as the initial value for the accumulator. foldl1 (\acc x -> acc + x) [1..5] -- 15 ---------------------------------------------------- -- 4. More functions ---------------------------------------------------- -- currying: if you don't pass in all the arguments to a function, -- it gets "curried". That means it returns a function that takes the -- rest of the arguments. add a b = a + b foo = add 10 -- foo is now a function that takes a number and adds 10 to it foo 5 -- 15 -- Another way to write the same thing foo = (+10) foo 5 -- 15 -- function composition -- the (.) function chains functions together. -- For example, here foo is a function that takes a value. It adds 10 to it, -- multiplies the result of that by 5, and then returns the final value. foo = (*5) . (+10) -- (5 + 10) * 5 = 75 foo 5 -- 75 -- fixing precedence -- Haskell has another function called `$`. This changes the precedence -- so that everything to the left of it gets computed first and then applied -- to everything on the right. You can use `.` and `$` to get rid of a lot -- of parentheses: -- before (even (fib 7)) -- true -- after even . fib $ 7 -- true ---------------------------------------------------- -- 5. Type signatures ---------------------------------------------------- -- Haskell has a very strong type system, and everything has a type signature. -- Some basic types: 5 :: Integer "hello" :: String True :: Bool -- Functions have types too. -- `not` takes a boolean and returns a boolean: -- not :: Bool -> Bool -- Here's a function that takes two arguments: -- add :: Integer -> Integer -> Integer -- When you define a value, it's good practice to write its type above it: double :: Integer -> Integer double x = x * 2 ---------------------------------------------------- -- 6. Control Flow and If Statements ---------------------------------------------------- -- if statements haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome" -- if statements can be on multiple lines too, indentation is important haskell = if 1 == 1 then "awesome" else "awful" -- case statements: Here's how you could parse command line arguments case args of "help" -> printHelp "start" -> startProgram _ -> putStrLn "bad args" -- Haskell doesn't have loops because it uses recursion instead. -- map applies a function over every element in an array map (*2) [1..5] -- [2, 4, 6, 8, 10] -- you can make a for function using map for array func = map func array -- and then use it for [0..5] $ \i -> show i -- we could've written that like this too: for [0..5] show -- You can use foldl or foldr to reduce a list -- foldl foldl (\x y -> 2*x + y) 4 [1,2,3] -- 43 -- This is the same as (2 * (2 * (2 * 4 + 1) + 2) + 3) -- foldl is left-handed, foldr is right- foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16 -- This is now the same as (2 * 3 + (2 * 2 + (2 * 1 + 4))) ---------------------------------------------------- -- 7. Data Types ---------------------------------------------------- -- Here's how you make your own data type in Haskell data Color = Red | Blue | Green -- Now you can use it in a function: say :: Color -> String say Red = "You are Red!" say Blue = "You are Blue!" say Green = "You are Green!" -- Your data types can have parameters too: data Maybe a = Nothing | Just a -- These are all of type Maybe Just "hello" -- of type `Maybe String` Just 1 -- of type `Maybe Int` Nothing -- of type `Maybe a` for any `a` ---------------------------------------------------- -- 8. Haskell IO ---------------------------------------------------- -- While IO can't be explained fully without explaining monads, -- it is not hard to explain enough to get going. -- When a Haskell program is executed, the function `main` is -- called. It must return a value of type `IO ()`. For example: main :: IO () main = putStrLn $ "Hello, sky! " ++ (say Blue) -- putStrLn has type String -> IO () -- It is easiest to do IO if you can implement your program as -- a function from String to String. The function -- interact :: (String -> String) -> IO () -- inputs some text, runs a function on it, and prints out the -- output. countLines :: String -> String countLines = show . length . lines main' = interact countLines -- You can think of a value of type `IO ()` as representing a -- sequence of actions for the computer to do, much like a -- computer program written in an imperative language. We can use -- the `do` notation to chain actions together. For example: sayHello :: IO () sayHello = do putStrLn "What is your name?" name <- getLine -- this gets a line and gives it the name "name" putStrLn $ "Hello, " ++ name -- Exercise: write your own version of `interact` that only reads -- one line of input. -- The code in `sayHello` will never be executed, however. The only -- action that ever gets executed is the value of `main`. -- To run `sayHello` comment out the above definition of `main` -- and replace it with: -- main = sayHello -- Let's understand better how the function `getLine` we just -- used works. Its type is: -- getLine :: IO String -- You can think of a value of type `IO a` as representing a -- computer program that will generate a value of type `a` -- when executed (in addition to anything else it does). We can -- store and reuse this value using `<-`. We can also -- make our own action of type `IO String`: action :: IO String action = do putStrLn "This is a line. Duh" input1 <- getLine input2 <- getLine -- The type of the `do` statement is that of its last line. -- `return` is not a keyword, but merely a function return (input1 ++ "\n" ++ input2) -- return :: String -> IO String -- We can use this just like we used `getLine`: main'' = do putStrLn "I will echo two lines!" result <- action putStrLn result putStrLn "This was all, folks!" -- The type `IO` is an example of a "monad". The way Haskell uses a monad to -- do IO allows it to be a purely functional language. Any function that -- interacts with the outside world (i.e. does IO) gets marked as `IO` in its -- type signature. This lets us reason about what functions are "pure" (don't -- interact with the outside world or modify state) and what functions aren't. -- This is a powerful feature, because it's easy to run pure functions -- concurrently; so, concurrency in Haskell is very easy. ---------------------------------------------------- -- 9. The Haskell REPL ---------------------------------------------------- -- Start the repl by typing `ghci`. -- Now you can type in Haskell code. Any new values -- need to be created with `let`: let foo = 5 -- You can see the type of any value with `:t`: >:t foo foo :: Integer -- You can also run any action of type `IO ()` > sayHello What is your name? Friend! Hello, Friend! ``` There's a lot more to Haskell, including typeclasses and monads. These are the big ideas that make Haskell such fun to code in. I'll leave you with one final Haskell example: an implementation of quicksort in Haskell: ```haskell qsort [] = [] qsort (p:xs) = qsort lesser ++ [p] ++ qsort greater where lesser = filter (< p) xs greater = filter (>= p) xs ``` Haskell is easy to install. Get it [here](http://www.haskell.org/platform/). You can find a much gentler introduction from the excellent [Learn you a Haskell](http://learnyouahaskell.com/) or [Real World Haskell](http://book.realworldhaskell.org/).