12.07.2015 Views

A Linguagem Funcional Haskell - Departamento de Informática e ...

A Linguagem Funcional Haskell - Departamento de Informática e ...

A Linguagem Funcional Haskell - Departamento de Informática e ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

A <strong>Linguagem</strong> <strong>Funcional</strong> <strong>Haskell</strong>Márcio M. Piffer , Rafael A. KrothCiências da Computação 3ª fase, 2002<strong>Departamento</strong> <strong>de</strong> Informática e EstatísticaUniversida<strong>de</strong> Fe<strong>de</strong>ral <strong>de</strong> Santa Catarina (UFSC), Brasil, 88040-900Fone (0XX48)333-9999, Fax (0XX48)333-9999m_piffer@inf.ufsc.br, coca@inf.ufsc.brRESUMOEste estudo tem como principal objetivo fazer uma breve introdução a linguagem <strong>de</strong>programação <strong>Haskell</strong>, sendo abordado em primeira instância alguns dos princípios básico dalinguagem, ou seja, on<strong>de</strong> esta foi fundamentada. Programar em uma linguagem funcional significabasicamente <strong>de</strong>finir funções e utilizar o computador para avaliar expressões. Falando <strong>de</strong>sta maneiranão imaginamos como a mais ascen<strong>de</strong>nte das linguagens funcionais do momento o <strong>Haskell</strong> po<strong>de</strong> serutilizado. Após a leitura <strong>de</strong>ste artigo espera-se que o leitor no mínimo compreenda conceitosbásicos, vantagens, e como a linguagem é utilizada.Palavras-chave: <strong>Haskell</strong>, <strong>Funcional</strong>, Lambda.ABSTRACTThis study has as main objective to do a brief introduction the programming language<strong>Haskell</strong>, being approached in first instance some of the basic of the language beginnings, that is tosay, where this was based. To program in a functional language means basically to <strong>de</strong>fine functionsand to use the computer to evaluate expressions. Speaking this way didn't imagine as the moreascendancy of the functional languages of the moment <strong>Haskell</strong> can be used. After the reading of thisarticle it is waited that the rea<strong>de</strong>r at least un<strong>de</strong>rstands basic concepts, advantages, and as thelanguage it is used.Key-words: <strong>Haskell</strong>, <strong>Funcional</strong>, Lambda.IntroduçãoExistem diversos paradigmas <strong>de</strong>programação e diversas linguagens associadas aestes paradigmas, e este trabalho irá enfatizar oparadigma <strong>de</strong> programação funcional e a linguagema ser abordada será o <strong>Haskell</strong>. O GHC (Glasgow<strong>Haskell</strong> Compiler) foi <strong>de</strong>senvolvido na universida<strong>de</strong><strong>de</strong> Glasgow na Escócia, ou seja, seu nascimento porassim dizer foi dado lá. Sua última versão é a 1.4 efoi <strong>de</strong>senvolvida por um grupo internacional atémarço <strong>de</strong> 1997, e está sendo administrada, ouaperfeiçoada na universida<strong>de</strong> <strong>de</strong> Yale.Princípios BásicosA linguagem a ser estudada é baseada quaseque totalmente no cálculo lambda ( λ ), sendo assimfica claro e evi<strong>de</strong>nte que aqueles que já possuírem


um conhecimento prévio <strong>de</strong>sta área terão uma maiorfacilida<strong>de</strong> no entendimento do artigo do que aquelesque são leigos no assunto citado.Outra questão interessante e que não po<strong>de</strong><strong>de</strong>ixar <strong>de</strong> ser dita é a <strong>de</strong> que quase todos osproblemas que são implementados em <strong>Haskell</strong> játiveram uma resolução indutiva construídaanteriormente.Conforme visto em [SCH 92] a indução éuma ferramenta muito po<strong>de</strong>rosa no<strong>de</strong>senvolvimento <strong>de</strong> algoritmos e esta geralmentetraz uma resolução elegante aos problemasapresentados. A Tese <strong>de</strong> Church, que não seráabordada aqui, comprova que todo e qualquerproblema resolvido imperativamente possui umresolução indutiva, ficando claro então que todosaqueles que quiserem se aventurar e conhecer o<strong>Haskell</strong> mais a fundo <strong>de</strong>veriam primeiramentepossuir um conhecimento prévio <strong>de</strong>stas duas áreas,cálculo lambda e indução.Tendo consciência também <strong>de</strong> que esta éuma linguagem extremamente tipada, torna-sesabido que para aqueles que já tiveram algumcontato como linguagens não tipadas como Perl,Tcl, ou Scheme, infelizmente terão uma dificulda<strong>de</strong>ainda maior para com o entendimento dalinguagem.Já aqueles que possuem algum tipo <strong>de</strong>experiência com linguagens tipadas como Java, C,Modula, ou até mesmo ML, irão ter maiorfacilida<strong>de</strong> no entendimento quanto ao sistema <strong>de</strong>tipos da linguagem apresentada neste trabalho.<strong>Haskell</strong> também é conhecido comocalculadora funcional e a forma <strong>de</strong> avaliação <strong>de</strong>expressões é <strong>de</strong> extrema importância, pois esta éque não <strong>de</strong>ixará que certas expressões resultem emnão-<strong>de</strong>terminismo. Todas as expressões sãoreduzidas tendo como base o cálculo lambda emaiores aprofundamentos sobre este po<strong>de</strong>m serencontrados em [THO 87].Toda e qualquer expressão em <strong>Haskell</strong> éavaliada como sendo uma equação matemática, ouseja, está po<strong>de</strong> ser construída, avaliada e resolvidautilizando-se sempre <strong>de</strong> leis algébricas.Qualquer expressão apresentada aocomputador será entendida como sendo um valor,sendo assim o papel do computador torna-se obter aforma normal ou mais reduzida possível <strong>de</strong>ste valore isto é feito através <strong>de</strong> b - reduções. Deduz-se entãoque o significado <strong>de</strong> uma expressão é seu valor e atarefa do computador é encontra - lo.Sessões e ScriptsAo passarmos uma expressão para esta seravaliada pelo computador o processo <strong>de</strong> avaliação eevolução é chamado sessão, sendo assim tendocomo prompt o ponto <strong>de</strong> interrogação (?). Algunsexemplos <strong>de</strong> sessão são apresentados abaixo.Exemplo 1:? 64 expressão apresentada64 valor <strong>de</strong> retorno apresentado ao usuárioExemplo 2:? 8*8 expressão apresentada64 valor <strong>de</strong> retorno apresentado ao usuárioNote que nos dois exemplos acima sãopassados expressões, a primeira já esta em suaforma normal, logo o computador não po<strong>de</strong> fazermais avaliações, então ele somente retorna o valor aapresentado, no entanto a segunda expressão po<strong>de</strong>rser avaliada e evoluída então ele, o computador, faza avaliação e evolução da expressão, até chegar auma forma normal e daí então retorna o valorencontrado. Concluímos então que uma sessão éiniciada com a passagem <strong>de</strong> uma expressão para ocomputador e só será terminada quando esteretornar algum valor.O nome Script é dado a área <strong>de</strong> <strong>de</strong>claração<strong>de</strong> funções e tipos, e alguns exemplos <strong>de</strong> <strong>de</strong>claração<strong>de</strong> tipos e funções serão dados logo a seguir, poresta razão não serão dados exemplos por enquanto.Valores e TiposSegundo [HUD 97] expressões <strong>de</strong>notamvalores e tipos <strong>de</strong> expressões são apenas termossintáticos que <strong>de</strong>notam tipos <strong>de</strong> valores ou só tipos.Todo valor possui um tipo associado, eintuitivamente po<strong>de</strong>mos pensar que tipos são<strong>de</strong>finições <strong>de</strong> valores.Valores em <strong>Haskell</strong> são consi<strong>de</strong>rados tiposprimários e po<strong>de</strong>m ser passados para funções comoargumentos, e estes irão retornar como respostascolocadas em estruturas <strong>de</strong> dados.Tipos por outro lado não são consi<strong>de</strong>radosprimários e trazem como sentido principal a<strong>de</strong>scrição <strong>de</strong> um valor. A associação <strong>de</strong> um tipo aum valor é chamada "typing".


Usando tipos e valores no exemplo abaixoescrevemos alguns typings.5 :: int‘a’ :: charO símbolo "::" <strong>de</strong>ve ser lido como "temtipo".Funções em <strong>Haskell</strong> geralmente são<strong>de</strong>finidos por uma série <strong>de</strong> equações, mas existe umtipo especial chamado "type signature <strong>de</strong>claration",que <strong>de</strong>clara um tipo explicito para a função.Um exemplo segue abaixo.inc :: int → int "type signature <strong>de</strong>claration".As "type signature <strong>de</strong>claration" não são <strong>de</strong>uso obrigatório, mas regras geralmente sãoutilizadas pelo programador para que este saiba quetipo possui cada função.Quando queremos <strong>de</strong>monstrar que umaexpressão e 1 é avaliada ou "reduzida" para umaoutra expressão e 2 , nós indicamos <strong>de</strong>sta maneiraque se segue:e 1 ⇒ e 2Por exemplo note que:inc (inc 3) ⇒ 5Tipos PolimórficosTipos monomórficos são encontramos commuita frequência em diversas linguagens <strong>de</strong>programação, mas estes restrigem <strong>de</strong> certa forma acapacida<strong>de</strong> do programador.<strong>Haskell</strong> também incorpora tipospolimórficos - tipos que são universalmentequantificados em algum lugar e referem-se a todosos outros tipos.Expressões <strong>de</strong> tipos polimórficosessencialmente <strong>de</strong>screvem famílias <strong>de</strong> tipos. Porexemplo, (∀ a) [a] é a família <strong>de</strong> tipos consistindo<strong>de</strong>, para todo tipo a, o tipo <strong>de</strong> listas <strong>de</strong> a.Listas <strong>de</strong> inteiros [1, 2, 3], listas <strong>de</strong>caracteres [‘h’, ‘e’, ‘l’ , ‘l’, ‘o’], e até mesmo listas<strong>de</strong> listas <strong>de</strong> inteiros[[2], [4], [6]]. Todos sãomembros <strong>de</strong>sta família, ou seja, no momento queusarmos a variável a está po<strong>de</strong> ser <strong>de</strong> qualquer tiposendo <strong>de</strong>s<strong>de</strong> que todos sejam do mesmo tipo.<strong>Haskell</strong> não irá admitir algo como [‘b’ , 2 ]. Nota-seentão que através da <strong>de</strong>finição <strong>de</strong> uma função queutiliza tipos polimórficos construímos, ou temos aoportunida<strong>de</strong>, <strong>de</strong> construir uma função genérica,on<strong>de</strong> esta po<strong>de</strong>rá ser utilizada para qualquer família<strong>de</strong> tipos.Para fazermos a <strong>de</strong>claração <strong>de</strong> um tipopolimórfico não necessitamos explicitar por escritoo símbolo do quantificação universal (∀). Em outraspalavras todos os tipos <strong>de</strong> variáveis estãoimplicitamente quantificados.Listas são muito utilizados em linguagensfuncionais e são um ótimo veículo para quepossamos <strong>de</strong>monstrar os princípios dopolimorfismo.A lista [1, 2, 3 ] é um resumo da lista 1: (2:(3: [])), on<strong>de</strong> [] é lista vazia e : é o operador <strong>de</strong>infixação, é ele que adiciona o primeiro argumentopara a frente do segundo e assim por diante, e <strong>de</strong>stamaneira conseguimos <strong>de</strong>finir um lista.Ao <strong>de</strong>finirmos uma função que conta onúmero <strong>de</strong> elementos <strong>de</strong> uma lista, notamos asfacilida<strong>de</strong>s oferecidas por este sistema <strong>de</strong> tipos.Veja o exemplo abaixo:length :: [a] → intlength [] = 0length (x : xs ) = 1 + length (xs)Se prestarmos atenção a <strong>de</strong>finição é quaseque auto - explicativa. Nós po<strong>de</strong>mos ler a funçãocomo sendo "O tamanho da lista vazia é zero, e otamanho da lista cujo primeiro elemento é x e orestante e da lista é xs é 1 mais o tamanho <strong>de</strong> xs,passado novamente a esta função.A função length é um exemplo <strong>de</strong> funçãopolimórfica e sua "type signature <strong>de</strong>claration"<strong>de</strong>monstra isto. Sua gran<strong>de</strong> vantagem vem quando<strong>de</strong>pois <strong>de</strong> <strong>de</strong>finida esta po<strong>de</strong> ser aplicada a qualquertipo <strong>de</strong> lista e é isto que notamos no exemploabaixo, pois são passados para a mesma funçãodiversos tipos <strong>de</strong> listas entre elas listas <strong>de</strong> tipo [Int],Char], e até mesmo, [[Int]] lista <strong>de</strong> lista <strong>de</strong> inteiros.length [1, 2, 3] ⇒ 3length [‘a’, ‘b’] ⇒ 2length [[1], [2], [3], [4]] ⇒ 4Com tipos polimórficos, achamos quealguns tipos estão em um senso extremamente maisgeral que outros. Por exemplo o tipo [a] é mais geraldo que o tipo [Char].O Sistema <strong>de</strong> tipos <strong>Haskell</strong> possui duasimportantes proprieda<strong>de</strong>s: Primeira, toda expressãobem tipada é garantida para ter um único tipoprincipal (explicado abaixo), e a Segunda, é que otipo principal po<strong>de</strong> ser inferido automaticamente.Uma expressão ou função tipo principal é otipo menos geral, que, intuitivamente, "Contémtodas as instâncias da expressão". Por exemplo, otipo principal da função length é expressado como[a] → a; os tipos [b] → a, a → a , ou até mesmo <strong>de</strong>a são muito gerais, consi<strong>de</strong>rando que algum tipocomo [Int] → Int é mais especifico. A existência <strong>de</strong>


tipos principais únicos é a característica mínima dosistema <strong>de</strong> tipos Hindley-Milner, sendo que esteforma a base do sistema <strong>de</strong> tipos <strong>Haskell</strong>, ML,Miranda e a maioria das linguagens funcionais hojeconhecidas.Em comparação com linguagens <strong>de</strong> tiposmonomórficos como C, o leitor irá notar que opolimorfismo <strong>de</strong>senvolve expressões, e a inferênciadiminui a carga <strong>de</strong> tipos sobre os programadores.User-Defined TypesPara <strong>de</strong>finirmos nossos próprios tipos em<strong>Haskell</strong> usa-se a <strong>de</strong>claração data, ao qual estetrabalho tenta exemplificar <strong>de</strong> forma a tornar maiora compreensão do leitor.Um importante tipo que já esta pre<strong>de</strong>finidoem <strong>Haskell</strong>, é a <strong>de</strong>finição <strong>de</strong> tipos boleanos, mas sópara exemplificar iremos fazer a sua criaçãotomando como se este não existisse:data Bool = False | TrueO tipo <strong>de</strong>monstrado acima é Bool e possuiexatamente dois valores: Verda<strong>de</strong>iro e Falso. O tipoBool em <strong>Haskell</strong> possui a <strong>de</strong>nominação <strong>de</strong> tipoconstrutor, e True e False são chamadosconstrutores <strong>de</strong> dado, ou só construtores.Po<strong>de</strong>mos assim <strong>de</strong>finir diversos tipos.Similarmente po<strong>de</strong>mos <strong>de</strong>finir o tipo Cor:data Cor = Vermelho | Ver<strong>de</strong> | Azul | VioletaMas se pararmos e prestarmos atenção estasduas <strong>de</strong>finições <strong>de</strong> tipos são limitadas, ou seja, sãotipos enumerados, pois possuem um número finito<strong>de</strong> construtores <strong>de</strong> dado.Abaixo temos um exemplo com um únicoconstrutor <strong>de</strong> dados.data Point = Pt a aDefinindo o tipo <strong>de</strong> dado Point nãolimitamos o usuário, pois este po<strong>de</strong>rá <strong>de</strong>finirqualquer tipo <strong>de</strong> ponto.Um tipo como Point é freqüentementechamado <strong>de</strong> tuple type, sendo que neste caso este ésó um produto cartesiano (neste caso binário) <strong>de</strong>outros tipos. Tipos multi-construtor, como Bool eCor, são chamados (disjunto) união ou tipos soma,em contraste a tipos mono construtor.Mais importante, no entanto, é lembrar quePoint também é um exemplo <strong>de</strong> tipo polimórfico:para qualquer tipo t, haverá a <strong>de</strong>finição <strong>de</strong> pontoscartesianos que usam t como o tipo coor<strong>de</strong>nada.Note que o tipo <strong>de</strong> binário Pt é a → a →Point a, ou seja os tipos abaixo são válidos:Pt 2.0 3.0 :: Point FloatPt ‘a’ ‘b’ :: Point CharPt True False :: Point BoolNão po<strong>de</strong>mos esquecer <strong>de</strong> ressaltar que algocomo Pt ‘a’ 1 é sem tipo pois ‘a’ e 1 possuem tiposdiferentes sendo assim o próprio sistema <strong>de</strong> tipos<strong>Haskell</strong> durante a compilação irá acusar erro.É <strong>de</strong> extrema importância saber distinguir aaplicação entre construtor <strong>de</strong> dados para construirum valor e a aplicação <strong>de</strong> um tipo construtor paraconstruir um tipo. O primeiro formador acontece emtempo <strong>de</strong> execução e é como nós computamoscoisas em <strong>Haskell</strong>, já o segundo acontece em tempo<strong>de</strong> compilação e é parte do processo do sistema <strong>de</strong>tipos para assegurar tipos seguros.Existe também a possibilida<strong>de</strong> <strong>de</strong>construirmos tipos utilizando o mesmo nome para otipo construtor e para o construtor <strong>de</strong> dados, comovemos a seguir.data Point a = Point a aE já que estamos falando do sistema <strong>de</strong>tipos <strong>Haskell</strong> não po<strong>de</strong>mos <strong>de</strong>ixar <strong>de</strong> abranger tipossinônimos, sendo que estes são utilizados para<strong>de</strong>finir um mesmo tipo com outro nome, mas nãonovos tipos. Portanto tipos sinônimos criam umnovo tipo a partir <strong>de</strong> um antigo só que com outronome. Para que possamos criar tipos <strong>de</strong>sta maneirautilizamos a <strong>de</strong>claração type, como no exemploabaixo.type String = [Char]type Name = StringFunçõesComo toda e qualquer linguagem <strong>Haskell</strong>oferece funções pré-<strong>de</strong>finidas, mas seu maiorpotencial está <strong>de</strong>stinado ao programador, ou seja, alinguagem oferece muitos recursos a este, quanto acriação <strong>de</strong> novas funções. Alguns <strong>de</strong>ste recursos jáforam <strong>de</strong>monstrados no sistema <strong>de</strong> tipos, agorairemos abordar a parte funcional da linguagem.Não iremos abordar funções oferecidas pelalinguagem, pois nossa intenção não é ensinar aprogramar em <strong>Haskell</strong> e tão pouco ensinar a utilizarfunções pré-<strong>de</strong>finidas ou oferecidas pela linguagem.Geralmente quando <strong>de</strong>finimos uma funçãoem <strong>Haskell</strong> utilizamos um "type signature" emprimeiro lugar e na próxima linha iniciamos a<strong>de</strong>claração da função, como no exemplo que segue:add :: Int → Int → Int -- type signatureadd x y = x + y -- Corpo da função


Através <strong>de</strong>ste exemplo temos conhecimento<strong>de</strong> como são feitos comentários <strong>de</strong> linha. Utilizamosdois sinais <strong>de</strong> menos (- -) consecutivos e tudo quefor escrito após não será reconhecido pelocompilador.Após este breve comentário continuamosfalando sobre funções e por intermédio do mesmoexemplo, que é chamado <strong>de</strong> função <strong>de</strong> curried. Umaaplicação <strong>de</strong> add tem a forma add e 1 e 2 , e issoeqüivale a (add e 1 ) e 2 , <strong>de</strong>s<strong>de</strong> que a associação daaplicação da função seja para a esquerda. Em outraspalavras, aplicando add a um argumento, istoproduzirá uma nova função ao qual é então aplicadoo segundo argumento. Isto é consistente com o tipo<strong>de</strong> add; Int → Int → Int.Sendo assim nós po<strong>de</strong>mos re<strong>de</strong>finir afunção inc <strong>de</strong> um modo diferente da que<strong>de</strong>monstramos anteriormente, agora po<strong>de</strong>mosutilizar a função add. Esta maneira queapresentamos agora o é uma aplicação parcial <strong>de</strong>uma função curried.Inc = add 1Sendo a linguagem <strong>Haskell</strong> baseada quaseque totalmente no Cálculo Lambda, po<strong>de</strong>mos<strong>de</strong>finir as mesmas funções <strong>de</strong> maneira muito maisreduzida e simplificada, mas não iremos <strong>de</strong>monstrare ou entrar em <strong>de</strong>talhes pois exigiria, como jáfalamos antes, um conhecimento prévio do leitorsobre o cálculo lambda para que este conseguisseenten<strong>de</strong>r.Po<strong>de</strong>mos acompanhar o comportamento dafunção entendo o próximo exemplo.Add (add 2 3) 5 ⇒ 10O exemplo apresentado acima épraticamente auto-explicável, pois ao lermos eleenten<strong>de</strong>mos que "A função add recebe doisargumentos um é uma função e o outro um valorsendo que este já se encontra na sua forma normal,então basta ser feita a resolução do primeiroargumento sendo que este <strong>de</strong>ver retornar um valor eé isto que irá acontecer, sendo assim o próximopasso é a resolução da expressão". Repare que se oprimeiro argumento retorna-se um caracter ‘a’ porexemplo este erro seria encontrado, mas somenteem tempo <strong>de</strong> execução não <strong>de</strong> compilação.AplicaçõesSegue ainda uma listagem das áreas on<strong>de</strong>tem-se sido <strong>de</strong>senvolvido software utilizando alinguagem já referida.Fran (animation)Haskore (music)CGI programming in <strong>Haskell</strong>Happy (Parser generator)Derive (Automatic <strong>de</strong>rivation of classes from data<strong>de</strong>clarations)Tk Gofer (the Tk GUI library ported to Gofer, alanguage very similar to <strong>Haskell</strong>).ConclusãoConcluímos após um ano <strong>de</strong> estudo que<strong>Haskell</strong> além dos inúmeros recursos que trazembutido consigo e dos <strong>de</strong>mais que oferece,consegue hoje um crescimento extraordinário nomundo científico, sendo esta hoje a linguagemfuncional mais ascen<strong>de</strong>nte do momento, apesar <strong>de</strong>não ser a mais utilizada ainda.Foi <strong>de</strong>scoberto também através <strong>de</strong>ste estudoque um dos gran<strong>de</strong>s anseios da população da área <strong>de</strong>informática atualmente a portabilida<strong>de</strong>, é muito bemproporcionada pela linguagem pois esta trabalha emdiversos tipos <strong>de</strong> arquiteturas e sistemasoperacionais. Interpretadores ou compiladores<strong>Haskell</strong> "rodam" em quase todo hardware ousistema operacional existente hoje.Deduz-se também que o estudo <strong>de</strong> outrasáreas, afins é claro, torna-se necessário para umamaior compreensão <strong>de</strong> alguns problemas, e <strong>de</strong>ntreestas áreas po<strong>de</strong>mos citar a indução matemática,sendo que esta é <strong>de</strong> extrema importância não só parao aprendizado do <strong>Haskell</strong> mas em diversas outrasáreas. Esta afirmação é feita após a <strong>de</strong>scoberta <strong>de</strong>que existem estruturas na informática que possuemuma resolução extremamente elegante através daindução, entre eles estão árvores, listas, strings, e omais clássico <strong>de</strong>les o das Torres <strong>de</strong> Hannoi.Mais uma dica para quem quiser apren<strong>de</strong>resta nova linguagem é utilizar o Hugs uminterpretador pequeno e <strong>de</strong> gran<strong>de</strong> portabilida<strong>de</strong>.Este interpretador é um excelente veículo paraapren<strong>de</strong>r se apren<strong>de</strong>r <strong>Haskell</strong>.Nota Bibliográfica[HUD 97] HUDAK, Paul e PETERSON, John. AGentle Intoduction to <strong>Haskell</strong>. Los AlamosNational Laboratory, 1997.[SCH 92] SCHINEIDER, Gerardo. Uso <strong>de</strong> laInducción para el Diseño <strong>de</strong> Algoritmos. UTN.,Facultad Regional Concepión <strong>de</strong>l Uruguay,Argentina. 1992.


[THO 87] THOMPSON, Simon. An Introductionto Type Theory and Constructive Mathematics.Canterbury, Kent, U.K. 1987.http://www.haskell.org/

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!