Jump to content
joaomfs

Dar valores a variaveis

Recommended Posts

joaomfs

Em hakell no código do programa é possível dar valores a variáveis assim:

let total=lenght a

estive a testar no prelude e deu, a minha duvida é se também funciona no source de uma função

fiz no prelude

>let total=[1,2,3,4]

>let a=length total

>show a

>"4"

Share this post


Link to post
Share on other sites
pwseo

Não sei se compreendi bem a tua dúvida. Em Haskell podes atribuir nomes a determinados valores, como na maioria das linguagens de programação. Isso faz-se de forma muito simples:

answer = 42

Quando estás a utilizar o GHCi (provavelmente aquilo a que chamaste "Prelude"), tens que utilizar let antes da atribuição de valor (por motivos que não farão sentido nenhum para ti nesta fase; é melhor aceitar que é assim, pelo menos para já). Ainda assim, o que escreves no GHCi é um caso especial, não deves considerá-lo como sendo Haskell completamente normal (pelo menos para já)

Dentro de uma função tens duas formas de adicionar "variáveis": as expressões let..in (que são diferentes do let que usas no GHCi) e as cláusulas where.

Comecemos pelas let..in. Vamos utilizar o teorema de Pitágoras:

hyp :: Float -> Float -> Float
hyp a b =
 let c1 = a^2
     c2 = b^2
     soma = c1 + c2
 in  sqrt soma

O exemplo acima é um pouco exagerado, é perfeitamente possível construir a função hyp sem utilizar let..in, mas o nosso objectivo é utilizar. Como podes ver, eu criei "variáveis" novas (c1, c2 e soma); a própria soma é definida em termos de outras variáveis. Quando utilizas let..in, as definições que criares mantêm-se visíveis dentro de toda a expressão que escreves após o in (neste caso, a expressão era sqrt soma).

Existem, no entanto, casos onde o scope da forma let..in não nos é suficiente, e queremos definições que sejam visíveis em várias expressões, como por exemplo numa função com múltiplas equações com guards (não podemos utilizar let..in fora das guards). Vou exemplificar com a fórmula quadrática:

quad :: Float -> Float -> Float -> [Float]
quad a b c
 | delta <  0 = []              -- sem soluções em R
 | delta == 0 = [ -b / (2*a) ]  -- uma solução em R
 | delta >  0 = [ (-b + sqrt delta) / (2*a)
                , (-b - sqrt delta) / (2*a) ]
 where
   delta = b^2 - 4 * a * c

Neste caso, queremos que delta seja visível em todos os casos que definirmos; com let..in isso seria impossível. Esta diferença deve-se ao facto de let..in constituir uma expressão, enquanto que where é uma estrutura sintáctica que faz parte da declaração de funções -- no futuro isto fará mais sentido. Para já convém que saibas que quando se usam guards, é provavelmente mais acertado utilizar where.

Mais uma nota: o primeiro caso podia ser resolvido também com where em vez de let..in. Pessoalmente, até acho que fica mais legível assim:

hyp :: Float -> Float -> Float
hyp a b = sqrt soma
 where soma = c1 + c2
       c1   = a^2
       c2   = b^2

Um pequeno reparo antes de terminar: quando damos um nome a um valor (em Haskell), é impossível atribuirmos esse nome a um valor diferente. Possivelmente isso já te foi explicado nas aulas: em Haskell os objectos são imutáveis (em teoria, claro está).

PS.: Ficou maior do que esperava. Caso não tenha sido esta a tua pergunta, seria bom que te explicasses melhor.

  • Vote 2

Share this post


Link to post
Share on other sites
thoga31

@joaomfs, após esta excelente explicação do @pwseo, gostaria de saber que background tens em programação. Parece-me que vens de uma linguagem estruturada, mas posso estar enganado. Digo isto porque, tipicamente, este tipo de questões vêm de pessoal com anterior experiência em linguagens como C, Pascal, Python e afins.

Uma noção importante a ter é que, em Haskell, não há a noção exacta de variável: se reparaste, o @pwseo utilizou sempre aspas quando se referiu a variáveis, e penso ser importante frisar porquê.

Como ele disse, em Haskell, e teoricamente, os objectos são imutáveis.

Portanto, e tendo em conta que o GHCi é apenas um interpretador interactivo em tempo real, tu podes definir valores, mas não os podes mudar.

foo = 60

-- Objectivo: mudar o valor de "foo"
fn x =  -- impossível, "foo" é imutável

Claro que no GHCi podes ir mudando o valor de "foo", mas como disse o @pwseo, o GHCi é um caso à parte e especial.

Acho que o @pwseo já te deu um bom esclarecimento, e com este meu post espero que tenhas ficado esclarecido. Creio que a tua dúvida se centrava nisto.

Cumprimentos.

  • Vote 1

Knowledge is free!

Share this post


Link to post
Share on other sites
joaomfs

a função que estou a trabalhar é a seguinte:

gerapecas :: (Int,Int,Int,Int,Int) -> Maybe IO ()
gerapecas (total,totN,totC,totE,totB) = 
    |total==36 = Nothing
|Just do 
x<- ramdomRIO(1,4)
  |x==1 && totB /= 6 = do nexttile <- B
  return()
  |x==2 && totC /= 2 = do nexttile <- C
                   return()
  |x==3 && totE /= 18 do nexttile <- E
return()
       |x==4 && totN /= 10 do nexttile <- N
  return()
|otherwise = gerapecas (total,totN,totC,totE,totB) 

where total =lenght getTiles
totB =lenght tiraB
     totC =lenght tiraC
     totE =lenght tiraE
     totN =lenght tiraN

pondo assim a função está bem defenida?

Obrigado pela ajuda

Ando no 1 ano na um e tenho de apresentar um projeto em haskell no qual tenho as ideas um pouco baralhadas, como disseste venho de outro tipo de linguagem no 12 costumava fazer umas brincadeiras em vb por isso é que me surgiu esta duvia, obrigado aos dois pela explicação

Edited by pwseo
Adicionadas tags CODE

Share this post


Link to post
Share on other sites
pwseo

Qual é o objectivo da tua função? (já agora, tem vários erros que impedem sequer que seja compilado o código)

Share this post


Link to post
Share on other sites
thoga31

Bom, primeiro que nada a indentação está terrível, ainda para mais quando o Haskell é sensível à indentação - tem regras muito bem definidas nesse aspecto. De seguida, isso não vai compilar uma vez que está com imensos erros.

Nota-se perfeitamente que estás a tentar fazer do Haskell uma linguagem como VB. O meu primeiro conselho é esqueceres o tipo de raciocínio que levavas em VB: em Haskell a história é muito diferente. Em Haskell não há variáveis! Não tentes simular isso.

Esclarece-me lá uma coisa: qual é o objectivo dessa função e onde está nexttile?

Edited by thoga31

Knowledge is free!

Share this post


Link to post
Share on other sites
joaomfs

o objetivo é gerar uma tail a ser jogada num jogo chamado carcassonne , o jogo é uma versão modificada que tem 4 tipo de tails que sãoi: (B)são 6, ©são 2, (E)são18 e as tipo (N) são10 as tails tem no total são 36, com isso criei as funçoes

-- | The 'getTiles' function returns a list of 'Element'
-- that represent a tile.
getTiles :: Element -> [Element]
getTiles el = findElements (unqual "tile") el

-- forma a lista com a apena a tile tipo B (mosteiro)
-- apartir da lista de element

tiraB :: [Element] -> [Char]
tiraB [] = []
tiraB x:xs = if x == B then x : tiraB xs
   else tiraB xs

-- forma a lista com a apena a tile tipo C (so cidade)
-- apartir da lista de element

tiraC :: [Element] -> [Char]
tiraC [] = []
tiraC x:xs = if x == C then x : tiraC xs
            else tiraB xs

-- forma a lista com a apena a tile tipo E (cidade canto)
-- apartir da lista de element

tiraE :: [Element] -> [Char]
tiraE [] = []
tiraE x:xs = if x == E then x : tiraE xs
            else tiraE xs

-- forma a lista com a apena a tile tipo N (cidade curva)
-- apartir da lista de element

tiraN :: [Element] -> [Char]
tiraN [] = []
tiraN x:xs = if x == N then x : tiraN xs
            else tiraN xs

dai o meu código onde inicialmente o programa via se ja tivessem sido lançadsa todas as tails eles não dava nada, senão gerava numeros de 1 a 4 onde o 1 representa o B, 2 representa o C, 3 representa o E e por fim o 4 representa o N

depois ele ia comparar o numero gerado com os tamanhos das listas acima, e caso uma das condiçoes da função gerapecas se verificasse a tai a ser gerada seria a correspondente ao numero gerado, se nunhuma se verificase ele geraria outra vez outra tail ate dar.

Fiz o melhor possivel para me explicar :S

Edited by thoga31
Tags code + GeSHi

Share this post


Link to post
Share on other sites
thoga31

Tu e o @angelicous estão a trabalhar no mesmo projecto, e ambos dedicam-se a grandes explicações :D

Obrigado por explicares isso tudo, mas o objectivo da outra função é então qual? Gerar peças aletaoriamente? Sob que algoritmo?

Aquela função está totalmente influenciada pelo raciocínio que tens de VB, e esse é um problema que tens de resolver o quanto antes. Nada de usar do quando tal é desnecessário.


Knowledge is free!

Share this post


Link to post
Share on other sites
joaomfs

Sim o objetivo é gerar peças aleatoriamente em função das que ja sairam o algoritmo que tento usar para as gerar é o gerapecas

Share this post


Link to post
Share on other sites
thoga31

gerapecas é a função e não o algoritmo. Eu vejo aquela função e não entendo bem o seu objectivo e funcionamento pois desconheço metade das coisas. Nem sequer entendo o que estás a tentar fazer com nexttile. Isto em parte acontece porque estás a escrever Haskell incorrecto naquela função, e acrexcentado ao facto de estares a tentar simular o estilo de VB, complica as coisas ainda mais.

Explica-me 1) quais são os argumentos da função, 2) os casos destes argumentos válidos e inválidos, 3) qual o output que a função deve dar, 4) o algoritmo que usas para determinar esse resultado.

Enquanto eu não entender isto, não consigo ajudar, nem eu nem ninguém. Eu não te posso ajudar a fazer uma função se nem sequer compreendo a 100% qual o output esperado. Um Maybe IO? E o que vais fazer com esse resultado?

Agora centra a tua explicação na função gerapecas e não no resto das funções. Em vez de dares o código delas, diz-me apenas o que é que elas retornam de forma sucinta.


Knowledge is free!

Share this post


Link to post
Share on other sites
joaomfs

1)os argumetos da função são o total das peças de cada tipo e o total de todas as peças,2) os argumentos são validos se o total das peças for <=36, o total de cada tipo de peça for <= ao total dessas peças 3) o output se o total das peças for 36 não deverá dar nada (ou poderá dar um caracter F de fim), senão dependendo do resultado do random devera ser o tipo da tail que foi gerado no random, 5) o algoritmo é o seguinte em primeiro vejo se todas as peças ja foram jogadas, se sim então a devolvo o resultado F, se não gero um numero de 1 a 4 e depois comparo esse numero com o total de cada tipo de peça se me der um numero correspondente a peça "X" e as peças desse tipo ja tiverem saido todas então gero outro numero de 1 a 4 e comparo novamente, se as peças do tipo "X" não tiverem saido todas o output devera ser o tipo dessa peça.

Obrigado.

Share this post


Link to post
Share on other sites
thoga31

Ham... como estás a pensar chamar a função? Precisas mesmo de um tuplo de cinco Int's como argumento? Segundo parece, tu estás a definir os valores deles com a cláusula where, portanto não entendo o porquê de eles serem argumento da função.

De seguida, porque é que o tipo de dados da função é Maybe IO?

O que é nexttile? Não está definido na função.

Outra coisa é a função RandomRIO - devolve um IO Int e tu estás a usar como se devolvesse Int.


Knowledge is free!

Share this post


Link to post
Share on other sites
joaomfs

era isso que estava a fazer com o nexttile que me dava o resulatdo da funçao depois fazia uma função que tilnha como argumento o "valor" do nexttile e inseria uma determinda coisa num xml dependendo desse valor,

Ha entao os argumentos da função tendo o where não é necessario defeni-los ?

Como faço então para devolver só um tipo Int?

Share this post


Link to post
Share on other sites
thoga31

Então como devolves o resultado da função com nexttile?

Está aí uma confusão qualquer, acho que estás a pensar muito ao estilo de VB. Cada função tem de fazer a sua coisa e terá o seu resultado. O objectivo da função gerapecas é essencialmente devolver uma peça de forma aleatória. Então, tens de o devolver. Aqui não tens variáveis, pelo que não podes atrribuir nada a nexttile para ser usado noutro local.

Algo que tens de entender e encaixar bem é que em Haskell os objectos são imutáveis. Nesta linha, tens de perceber que não há variáveis como noutras linguagens.

Se queres usar o valor de gerapecas, tens de chamar a função e usar o seu resultado. Este resultado não será guardado em lado nenhum.

Se tiveres de usar o valor da função para mais do que uma coisa, tens de executar essas coisas de uma vez só.

Em suma:

foo a b = -- whatever

bar x y = let z = foo x z
         in map (\f -> f z) [fn1, fn2, fn3]

Edited by thoga31
Remoção de uma heresia haskelliana xD

Knowledge is free!

Share this post


Link to post
Share on other sites
pwseo

joaomfs,

Se bem percebi tu tens uma espécie de "saco com peças" (que já agora são chamadas "tiles" e não "tails") e queres devolver uma delas aleatoriamente, correcto?

Se sim, então o caminho a seguir é uma função recursiva na qual vais transportando a lista de peças restantes de invocação para invocação, algo deste género:

func :: [Tile] -> IO ()
func [] = return ()  -- se não há tiles, não há nada a fazer
func ts = do
 r <-  -- gerar um número aleatório
 let t =  -- seleccionar t em ts
 let ts2 =  -- remover t de ts

 -- aqui fazes o que tiveres a fazer com t

 func ts2  -- chamar recursivamente a função

Parece-te bem? Isto implica teres previamente uma lista de todos os tiles disponíveis para escolha (são apenas 36, não será problema nenhum).

Nota: O resultado da função é IO () porque a geração de números aleatórios funciona dentro do IO (e o () indica que não queremos devolver nada da função).

Edited by pwseo
  • Vote 1

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.