Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #57 da revista programar. Faz já o download aqui!

Nazgulled

[Haskell] Converter um IO Int para um Int

Mensagens Recomendadas

Nazgulled    8
Nazgulled

Estou aqui com um poroblema gravissimo que me esta a impedir a continução deste trabalho para entregar até dia 2 e ainda vou no inicio...

Num determinado exercicio tinhamos de gerar numeros aleatorios e para isso, com uma pesquisa na net, desenvolvi o seguinte código:

-- Gera um número aleatório compreendido entre o par (x, y)
geraNumeroAleatorio :: (Int, Int) -> IO Int
geraNumeroAleatorio (x, y) =
do
	r <- getStdRandom $ randomR (x, y)
	return r

O problema esta em usar o valor devolvido por esta função para outros fins onde apenas tenho de usar Int e não IO Int. Por exemplo, criar uma lista de inteiros com vários numeros aleatorios e depois somar todos esses valores excluindo o mais baixo. Tudo isto era muito fácil se fosse uma lista de Int, numa lista de IO Int não consigo, mas eu preferia saber (se possível) como converter o valor devolvido pela função geraNumeroAleatorio do tipo IO Int para apenas Int.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    309
Rui Carlos

não sei se isso será possível... penso que só podes usar funções do tipo IO dentro de outras funções do tipo IO.

deixo-te aqui uma função semelhante à que tens mas que te calcula uma lista de n números aleatórios, talvez ajude...

geraN::Int->(Int,Int)->IO [int]
geraN 0 _    =return []
geraN n (x,y)=do l<-geraN (n-1) (x,y)
                 new<-randomRIO (x,y)
                 return (new:l)

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Nazgulled    8
Nazgulled

Que cena, se isso não dá pa fazer, cheira-me que nem um 1/4 do trabalho vou fazer...

Porque tipo, tens essa lista de IO [int], imagina, com 4 valores: [2, 3, 4, 5]. Agora, o objectivo é, usar essa lista, remover o 2 (número mais baixo) e somar os restantes, o resultado seria 12. Como faço eu isso?

Ou seja, nesta situações, de usar sempre IO Int, não vou puder usar a função sum, vou ter de criar a minha função sumIO, certo? Isto vai acontecer o mesmo para todas as outras funções que eu pretenda usar que já estejam definidas no haskell, não vou puder usar porque não funcionam com IO Int.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    309
Rui Carlos

podes fazer tudo o que fazia se não fosse com IO, só dá um pouco mais de trabalho...

f::IO Int
f=do l<-geraN 4 (1,10)
     let l1=removeMenor l
     let soma=sum l1
     return soma

esta função gera 4 números entre 1 e 10 aleatoriamente, remove o menor (através da função não monádica removaMenor, que terás de definir), soma os restantes valores e devolve essa soma.

o operador '<-' permite-te ir buscar o resultado de uma função monádica.

o operador 'let ... =' é usado com as não monádicas.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Nazgulled    8
Nazgulled

Ok, acho que já tou a entrar na cena mas continuo com algumas questões:

1)

Qual a diferença entre eu usar r <- getStdRandom $ randomR (x, y) e new<-randomRIO (x,y)? O caso azul é o que tu me disseste, o a vermelho foi o que eu vi na documentação oficial do Haskell. Qual a diferença e qual o modo recomendado?

2)

Imagine-se o seguinte código:

type ABC = IO (Int, Int, Int)

geraABC :: ABC
geraABC =
do a <- 4
   b <- 2
   c <- 5
   return (a, b, c)

mostraABC :: ABC -> IO()
mostraABC (x, y, z) =
do putStrLn "A: "
   putStrLn (show x)
   putStrLn "B: "
   putStrLn (show y)
   putStrLn "C: "
   putStrLn (show z) 

O objectivo seria compilar correctamente, carregar o ficheiro e fazer o seguinte:

abc <- geraABC

mostraABC abc

e apresentar os resultados no ecrã, mas isto não funciona porque dá o seguinte erro:

Couldn't match `IO (Int, Int, Int)' against `(a, b, c)'

      Expected type: IO (Int, Int, Int)

      Inferred type: (a, b, c)

    When checking the pattern: (x, y, z)

    In the definition of `mostraABC':

        mostraABC (x, y, z)

                    = do

                        putStrLn "A: "

                        putStrLn (show x)

                        putStrLn "B: "

                        putStrLn (show y)

                        putStrLn "C: "

                        putStrLn (show z)

Tentei substituir o type inicial por:

data ABC = IO (Int, Int, Int) | (Int, Int, Int)

Mas dá erro a dizer que não é válido. O que me está escapar para ter este pequeno código a funcionar? (Claro que o verdadeiro exercicio não é este, isto é só um exemplo pequeno para ser mais fácil ajudarem-me).

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    309
Rui Carlos

relativamente à primeira questão, eu fui à documentação do GHC e encontrei uma função que fazia o que era preciso (gerar números aleatórios) e usei essa função. a modo recomendado é aquele que tu entenderes melhor (ainda não entendi bem a tua solução, em principio e só ver a documentação que está no site, mas acho a minha solução mais simples).

quanto à questão dois, (x,y,z) é uma coisa do tipo (a,b,c) e não IO (a,b,c).

aliás, quando fizeres 'abc<-geraABC' vais ficar com uma variável do tipo (a,b,c). o efeito do operador '<-' é extrair o resultado de uma monad.

podes fazer da seguinte forma:

mostra::IO ()
mostra=
  do (x,y,z)<-geraABC
     putStrLn "A: "
     putStrLn (show x)
     ...

deve resolver o problema.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Nazgulled    8
Nazgulled

Isso não vai resolver bem o meu problema porque tipo: Na minha função geraABC, eu tenho valores fixos, mas era só um exemplo, estes valores irão ser aleatorios, logo eu quero puder fazer algo do genero:

a <- geraABC
b <- geraABC
c <- geraABC
(...)

e depois chamo a função que mostra os valores do a, b ou c, conforme me apetecer, não quero gerar estes valores quando for chamar a função que irá mostrar os valores, logo tenho de passar como parametro na função "mostra" algo do tipo ABC. Ai é que esta o problema... por isso é que tentei a cena do Data, ter dois tipos de dados, mas não parece funcionar...

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
kAIOSHIN    0
kAIOSHIN

Boas!

Bem...Parece-me que também estás a fazer o trabalho de P.F. :biggrin:

Afinal sempre conseguiste transformar numa lista de inteiros?

A funçao que o Rui Carlos fez que dá uma lista com n ºs aleatorios já chega para fazer os atributos do agente. Tipo, basta gerares uma lista com 4 números a variar entre 3 e 18 (o minimo e maximo de qualquer atributo)

Mas gostava mesmo é de saber transformar numa lista de Inteiros, para depois poder usar os atributos na formula dos modificadores... :dontgetit:

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Nazgulled    8
Nazgulled

sim, já resolvi os problemas todos que tinham criado neste tópico...

A solução para o problema que mostrei no meio do topico pode passar pelo seguinte, porque eu tava a fazer uma confusão tremenda:

type ABC = (Int, Int, Int)

geraABC :: IO ABC
geraABC =
do a <- 4
   b <- 2
   c <- 5
   return (a, b, c)

mostraABC :: ABC -> IO()
mostraABC (x, y, z) =
do putStrLn "A: "
   putStrLn (show x)
   putStrLn "B: "
   putStrLn (show y)
   putStrLn "C: "
   putStrLn (show z) 

Compara os 2 e vê as diferenças, esta apenas nos IOs, não sei se isto te ajuda ou não porque não percebi bem a tua dúvida.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
kAIOSHIN    0
kAIOSHIN

Bem, a minha dúvida é a seguinte. Nós temos lá a formula de modificação [(X-10)/2] certo? Preciso que os valores gerados anteriormente sejam Int, não?

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
[d-_-b]    0
[d-_-b]

pessoal tb estou a fazer esse trabalho e ja terminei... so falta o relatorio em latex... vejam se isto ajuda:

d6 = do getStdRandom (randomR (1,6))

geraCaract = do a <- d6;
                b <- d6;
                c <- d6;
                d <- d6;
                return (sum (tail (sort [a,b,c,d])))

ja agora... como passo esta ultima funcao tipo... sem parentises e com pontos?

Abraço, Pires

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    309
Rui Carlos
' timestamp='1167351404' post='73138']

ja agora... como passo esta ultima funcao tipo... sem parentises e com pontos?

Abraço, Pires

sum.tail.sort$[a,b,c,d]

penso que isto deve funcionar...

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
kAIOSHIN    0
kAIOSHIN

Boas pessoal. Estou a ficar lixado... Acho que só me falta mesmo isto para conseguir fazer o resto do trabalho. Como é que conseguiram fazer, por exemplo a tarefa 6? A função recebe Int, mas os valores gerados aleatóriamente não sao Int. A função que o Pires fez ligeiramente modificada:

d6 :: Int -> Int -> IO Int
d6 x y =  randomRIO (x,y)

geraCaract = do          
               a <- d6;
               b <- d6;
               c <- d6;
               d <- d6;
               return (a,b,c,d)

Isto não devia de funcionar? Dar Inteiros? A mim dá-me este erro:

*** Binding             : geraCaract

*** Outstanding context : Monad ((->) Int)

Espero que tenham percebido a dúvida.. Qualquer ajuda é bem-vinda...Abraço

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
kAIOSHIN    0
kAIOSHIN

ok..obrigado. Só que agora quero usar os inteiros gerados aqui:

modifiers :: Agente -> Modificador
modifiers (a,b,c,d,_) = (truncate(((fromIntegral a)-10)/2),
                        truncate(((fromIntegral b)-10)/2),
                        truncate(((fromIntegral c)-10)/2),
                        truncate(((fromIntegral d)-10)/2)
                       )

*** Term : geraCaract

*** Type : IO (Int,Int,Int,Int)

*** Does not match : (Int,Int,Int,Int,Int)

Ele gera IO (Int...) e não Int só... :confused:

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
ricardo_bcl    0
ricardo_bcl

Meus amigos vou vos dar a conhecer uma função que "transforma" um IO a num a, mas que na cadeira em que eu descobri isto (Métodos de Programação 1 do 2º ano) dizia para não utilizar isto, por razões que agora não vou dizer...

Mas o que é facto, é que dá jeito às vezes... lol

Façam  import System.IO.Unsafe

E a dita função é unsafePerformIO, que é do tipo:

unsafePerformIO :: IO a -> a

Mas digo-vos que pode-se escrever os programas em haskell sem usar isto. Por acaso usei uma vez num caso em que não consegui dar-lhe a volta, mas o vosso trabalho de PF (o rpg) não precisa disto...

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Nazgulled    8
Nazgulled

este tópico ficou assim um bocado confuso... só não percebo como é que ainda não solucionaram esse problema, a resposta está algures por aqui, eu já consegui resolver a minha dúvida com a ajuda do Rui Carlos. foi pelo messenger, ms de qq forma, tem neste tópico o exemplo que eu tava a ter problemas e o mesmo exemplo solucionado, portanto...

a não ser que a vossa dúvida seja diferente.

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Rui Carlos    309
Rui Carlos
' timestamp='1167766676' post='74065']

Eu resolvi o meu problema, já acabei o trabalho... Mas só usando o unsafePerformIO é que consegui o que pretendia.

Abraço

acho que os profs não vão achar muita piada à utilização dessa função...

EDIT:

isso está mesmo a funcionar?

neste código

module Teste where

import System.IO.Unsafe
import System.Random

f=do res <- randomRIO (1,10)
     return res

g=unsafePerformIO f

ele só executa a função randomRIO uma vez!!!

ou seja, a função g que devia dar valores aleatórios, gera sempre o mesmo valor em cada execução do ghci!

*Teste> g

1

*Teste> g

1

*Teste> g

1

*Teste> g

1

*Teste> g

1

*Teste> g

1

*Teste> g

1

*Teste> g

1

*Teste> f

10

*Teste> f

7

*Teste> f

9

*Teste> f

7

*Teste> f

9

*Teste> f

4

aconselho a leitura da documetação do GHC (ou do interpretador/compilador que estiverem a usar) para não terem surpresas: http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-IO-Unsafe.html#v%3AunsafePerformIO

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
kAIOSHIN    0
kAIOSHIN

Nós precisavamos de um "agente" com valores que fossem gerados aleatoriamente. Uma vez que o agente não muda até ao fim da aventura, pudemos usar o unsafePerformIO.

Fiz do seguinte modo

type Agente = (Int,Int,Int,Int,Int)

agente :: Agente
agente = (forca,destreza,inteligencia,carisma,500)

d318 :: IO Int
d318 =  randomRIO (3,18)

forca :: Int
forca = unsafePerformIO d318

destreza :: Int
destreza = unsafePerformIO d318

inteligencia :: Int
inteligencia = unsafePerformIO d318

carisma :: Int
carisma = unsafePerformIO d318

Pode não ser a maneira correcta, mas foi a única em que consegui o que pretendia: 4 Int!  :-[

Abraço

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora


×

Aviso Sobre Cookies

Ao usar este site você aceita a nossa Política de Privacidade