Skip to content

Instantly share code, notes, and snippets.

@halan
Last active November 3, 2016 13:33
Show Gist options
  • Save halan/d0369e697a9f68e59af13db18f7bf084 to your computer and use it in GitHub Desktop.
Save halan/d0369e697a9f68e59af13db18f7bf084 to your computer and use it in GitHub Desktop.
Algoritmo de Lunh para calcular CPF e CNPJ. (também segue o mesmo algoritmo reescrito em Haskell. A versão em Haskell tem uma aparência ligeiramente mais simples devido a recursos como guardas, listas de compreensão e ciclos...)
import Html exposing (text, p, div)
-- based on https://en.wikipedia.org/wiki/Luhn_algorithm
lunh : ( Int -> Int ) -> Int -> List Int -> List Int
lunh f len nums =
let
cycles = ceiling (toFloat len / (toFloat (List.length nums)))
cycle nums len =
nums
|> List.repeat cycles
|> List.concat
|> List.take len
cycle1to9 = cycle [2 .. 9]
lunhSum len nums =
nums
|> List.reverse
|> List.map2 (*) (cycle1to9 len)
|> List.sum
in
if List.length nums == len then nums
else nums
|> lunhSum len
|> \n -> (f n) :: List.reverse nums
|> List.reverse
|> lunh f len
-- Mod 11 rule based on https://pt.wikipedia.org/wiki/D%C3%ADgito_verificador#M.C3.B3dulo_11
mod11 : Int -> Int
mod11 total =
total
|> \n -> n % 11
|> \n -> (if n < 2 then 0 else 11 - n)
-- CPF is a Lunh (module 11) of 11 digits
generateCPF : List Int -> List Int
generateCPF = lunh mod11 11
-- CNPJ is a Lunh (module 11) of 14 digits
generateCNPJ : List Int -> List Int
generateCNPJ = lunh mod11 14
main =
div []
[
p []
-- Let's try some CPF and put on the screen
[ [1,1,1, 2,2,2, 3,3,3]
|> generateCPF
|> toString
|> text
]
, p []
-- And some CNPJ
[ [1,8,9,5,7,0,9,0,0,0,0,1]
|> generateCNPJ
|> toString
|> text
]
]
{-
Haskell version BASED on my Elm implementation
-}
-- based on https://en.wikipedia.org/wiki/Luhn_algorithm
lunh :: ( Int -> Int ) -> Int -> [Int] -> [Int]
lunh f len nums
| length nums == len = nums
| otherwise
= let
lunhSum len nums = sum [ y*x | (x,y) <- zip (cycle1to9 11) (reverse nums) ]
cycle' nums len = take len (cycle nums)
cycle1to9 = cycle' [2 .. 9]
in lunh f len
. reverse
. (\n -> (f n) : reverse nums)
. lunhSum len
$ nums
-- Mod 11 rule based on https://pt.wikipedia.org/wiki/D%C3%ADgito_verificador#M.C3.B3dulo_11
mod11 :: Int -> Int
mod11 total
= (\n -> if n < 2 then 0 else 11 - n)
$ total `mod` 11
-- CPF is a Lunh (module 11) of 11 digits
generateCPF :: [Int] -> [Int]
generateCPF = lunh mod11 11
-- CNPJ is a Lunh (module 11) of 14 digits
generateCNPJ :: [Int] -> [Int]
generateCNPJ = lunh mod11 14
main =
putStrLn . show . generateCPF $ [1, 1, 1, 2, 2, 2, 3, 3, 3]
@sinapinto
Copy link

file extensions confused me for a sec :P

@halan
Copy link
Author

halan commented Oct 19, 2016

Thanks, I fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment