Jump to content
angelicous

Como usar o random em uma lista de caracteres?

Recommended Posts

angelicous

Nunca usei o random no Haskell, e o tipo de dados IO também não me é familiar.

Se tiver uma lista de caracteres ['a','b','c'] como se usa o random para escolher e retornar aleatóriamente um deles?

Existe diferença num random de lista de caracteres e uma lista de strings? Se sim podem dar os dois exemplos?

Share this post


Link to post
Share on other sites
pwseo

O tipo de dados IO é uma forma que Haskell tem de "manter a pureza" das funções mesmo em casos de operações de input/output (que quebram a transparência referencial).

De resto, o IO funciona como uma espécie de embrulho: de cada vez que uma função te devolve um valor e precisou de realizar operações IO, devolve-te o seu resultado "embrulhado" no IO (ex.: IO Integer). O importante aqui é que só podes utilizar funções que devolvam tipos de dados IO a dentro de funções que devolvam tipos de dados também embrulhados no IO (é por isso que não consegues utilizar randomRIO numa função que devolva Int, mas consegues utilizá-la na main). Isto essencialmente assegura a pureza do teu código (nota: há formas obscuras de contornar isto tudo, mas não vale a pena falarmos disso).

Quanto ao resto da tua questão, podes facilmente gerar um numero aleatório entre 0..N-1 (sendo N o número de elementos de uma lista), e depois utilizas o operador !! para escolher esse elemento da lista.

lista = ['a'..'z']

main :: IO ()
main = do
 n <- randomRIO (0, (length lista) - 1)
 print $ lista !! n

Outro exemplo, desta vez com a lógica de selecção de um valor aleatório dentro de uma função separada:

-- Repara como o tipo de dados de retorno é 'IO a' e não apenas 'a'
pickFrom :: [a] -> IO a
pickFrom xs = do
 n <- randomRIO (0, (length xs) - 1)
 return $ xs !! n

main :: IO ()
main = do
 -- Como 'pickFrom' devolve 'IO a', temos que "desembrulhar" o IO e
 -- deixar o valor lá contido na variável 'c'
 c <- pickFrom ['a'..'z']
 print c

Como vês, escolher um elemento aleatório de uma lista não depende do tipo de dados contido na lista (a pickFrom aceita listas de qualquer tipo de dados).

Edited by pwseo

Share this post


Link to post
Share on other sites
angelicous

Hmm...

Então imaginemos o 1º caso.

Seria possível imprimir uma string e um IO no main?

Por exemplo de forma a que o output seja este: "Este é o valor aleatório:" ++ resultado de n

Share this post


Link to post
Share on other sites
pwseo

Tu não "imprimes um IO", porque não existe uma representação gráfica desse conceito. Mas podes imaginar um IO Int de valor 42 como sendo IO 42.

De qualquer forma, vamos aprofundar um pouco (mas não muito; ainda assim, vou escrever um pouco).

Em Haskell há um conceito que não precisas de compreender para já, que é o conceito de Monad. O que interessa saber aqui é que os tipos de dados IO a pertencem à classe Monad (Haskell tem classes, como já deves saber).

Adiante. Sempre que estamos a utilizar um tipo de dados que pertence à classe Monad*, a linguagem Haskell permite-nos utilizar a notação do, que nos permite escrever o nosso código de uma forma quase imperativa (no caso do monad IO).

Dentro desta notação, o operador <- pode ser utilizado para "extrair um valor puro" de um valor monádico**. Assim sendo, podemos fazer o seguinte:

main = do
 n <- randomRIO (1,5)
 putStrLn $ "Este é o valor aleatório: " ++ show n

A função randomRIO dá-nos um IO Int, mas o operador <- "extrai" o componente Int desse resultado e coloca-o dentro de n. Atenção: isto só é possível porque a função main funciona no monad IO; o operador <- só consegue "extrair" valores do mesmo monad em que está a funcionar.

Só para que fique claro, n tem tipo Int e não IO Int, porque utilizamos o operador <- para "desembrulhar" o valor original.

Eu sei que isto pode parecer estranho (especialmente se vieres de linguagens imperativas como C), mas com o tempo acaba por fazer sentido.

* Há vários tipos de dados que pertencem à classe Monad e que os iniciados normalmente não sabem: o Maybe e [] (listas) são Monads que permitem utilizações muito interessantes com a notação do, mas isso fica para outra altura.

** Dentro de um valor monádico pode estar outro monádico; imagina um valor monádico como um presente embrulhado: pode ter várias camadas de papel de embrulho (para simplificar consideramos apenas uma), e o que nos interessa está no meio.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.