Há alguns meses (em Maio, para ser mais exato), recebi uma mensagem de um estudante com um problema interessante para ser resolvido em Haskell. Dizia ele que o programa deveria receber como entrada um número de quatro dígitos e retorná-lo por extenso. Por exemplo, a entrada “0123″ deveria ter como resposta: “cento e vinte e três”.  Como estou com tempo sobrando (já fechei quase todas as matérias do semestre), resolvi brincar um pouco com esse problema, o que gerou este post.

Resolvi então fazer uma função extenso, que recebe uma string com quatro caracteres e retorna uma string:

extenso ([x,y,z,w]) = mil(x) ++ cen([x, y,z,w]) ++ dec([y,z,w]) ++ if(z == '1')then "" else uni(w)

A linha acima diz que extenso é a concatenação de mil(x), cen([x, y,z,w]), dec([y,z,w]) e if(z == '1')then "" else uni(w), que basicamente seria a concatenação da parte dos milhares, das centenas, das dezenas e das unidades. O “if” no final é para que a parte das unidades só fosse processada quando o valor das dezenas fosse diferente de ‘1′ (quando a dezena vale 1, a unidade é tratada junto com a dezena).
Vamos ver as outras funções:

mil(x):

mil(x) = (case x of
    '0' -> ""
    '1' -> "mil"
    '2' -> "dois mil"
    '3' -> "tres mil"
    '4' -> "quatro mil"
    '5' -> "cinco mil"
    '6' -> "seis mil"
    '7' -> "sete mil"
    '8' -> "oito mil"
    '9' -> "nove mil")

A função acima retorna a parte dos milhares. é bem simples, apenas retorna a parte dos milhares por extenso (e “” para  quando o valor dos milhares for zero).

cen([x, y,z,w]):

cen([x, y,z,w]) =  (if(not(x=='0') && ((y=='0' && (not(z=='0') || not(w=='0'))) || not(y=='0') && z=='0' && w == '0'))then " e " else "") ++ (case y of   
    '0' -> ""
    '1' -> (if (z == '0' && w == '0') then "cem" else "cento")
    '2' -> " duzentos"
    '3' -> " trezentos"
    '4' -> " quatrocentos"
    '5' -> " quinhentos"
    '6' -> " seiscentos"
    '7' -> " setecentos"
    '8' -> " oitocentos"
    '9' -> " novecentos") ++ if ((y=='0') || (z == '0' && w == '0')) then "" else " e "

Retorna a parte das centenas. o if inicial e o final tratam o aparecimento do “e” entre as palavras. Repare também no tratamento do ‘1′, que às vezes aparece como “cem” e outras como “cento”.

dec([y,z,w]):

dec([y,z,w]) = (case z of
    '0' -> ""
    '1' -> decDez(w)
    '2' -> "vinte"
    '3' -> "trinta"
    '4' -> "quarenta"
    '5' -> "cinquenta"
    '6' -> "sessenta"
    '7' -> "setenta"
    '8' -> "oitenta"
    '9' -> "noventa" ) ++ if(z == '0' || z== '1' || w == '0') then "" else " e "

decDez(w) = case w of
    '0' -> "dez"
    '1' -> "onze"
    '2' -> "doze"
    '3' -> "treze"
    '4' -> "quatorze"
    '5' -> "quinze"
    '6' -> "dezesseis"
    '7' -> "dezesete"
    '8' -> "dezoito"
    '9' -> "dezenove"

Aqui tratamos a parte das dezenas. Quando o valor for ‘1′, temos que fazer um tratamento especial, então usamos a função decDez(w). No final temos um if para tratar o uso do “e”.

uni(x):

uni(x) = case x of
    '0' -> ""
    '1' -> "um"
    '2' -> "dois"
    '3' -> "tres"
    '4' -> "quatro"
    '5' -> "cinco"
    '6' -> "seis"
    '7' -> "sete"
    '8' -> "oito"
    '9' -> "nove"

Finalmente, a função uni(x) cuida da parte das unidades.

Este problema é de fácil resolução, deixo como exercício para quem quiser brincar um pouco com listas. Bug do meu código: o valor “0000″ retorna “” (faltou tratar isso =P).

Blogged with the Flock Browser

Tags: , ,

Deixe uma resposta