Home

Sobre Text e OverloadedStrings

por Pedro Tacla Yamada

Essa é uma nota rápida para completar o dia 4 da série 24 dias de Hackage. Vou comentar brevemente sobre a extensão OverloadedStrings e os tipos String, ByteString e Text.

Você pode ter notado que Haskell tem mais de um tipo para representar texto. Isso é, de fato, um problema do ecossistema da linguagem, mas não vale a pena discutir as críticas a fundo. Como expliquei no primeiro post desse blog em português o literal [1, 2, 3] em Haskell é uma lista-ligada, não um Array. O tipo String em Haskell também é uma lista:

type String = [Char]

Você pode imaginar que isso causa problemas de performance, porque listas não são a melhor estrutura de dados para muitas tarefas relacionadas a processamento de texto.

Por isso, há dois pacotes que implementam tipos para strings com características diferentes:

Ambos os pacotes seguem a convenção de exportar funções pack que recebem uma String e retornam um Text ou uma ByteString. O que a extensão OverloadedStrings faz é usar uma type-class definida em Data.String chamada IsString. A type-class define:

class IsString s where
    fromString :: String -> s

Algumas implementações da type-class seriam:

instance IsString String where
    fromString = id

instance IsString Text where
    fromString = pack

Assim, quando escrevemos o literal "asdfasdf" no código a extensão vai reescrever isso como (fromString "asdfasdf"). Isso nos deixa ter "asdfasdf" :: String e "asdfasdf" :: Text. Na maior parte dos casos o compilador vai só inferir o tipo certo e as coisas vão funcionar fluidamente.


Outra extensão na mesma linha é OverloadedLists. Ela usa type-class IsList, que é basicamente definida como:

class IsList l where
    type Item l
    fromList :: [Item l] -> l

Isso quer dizer que uma instância para um “tipo alvo” tem que definir um tipo de elemento e poderemos converter literais de listas desse tipo para o “tipo alvo”. Em outras palavras, se queremos escrever Sets do Data.Set como listas, adicionamos a instância:

import qualified Data.Set

instance (Ord a) => IsList (Data.Set.Set a) where
    type Item (Data.Set.Set a) = a
    fromList = Data.Set.fromList

Ao ativar a extensão se pode escrever

[1, 2, 3, 4] :: Data.Set.Set

Conhecendo essas extensões o problema não parece tão ruim assim. Acabo de mostrar uma forma com a qual Haskell nos deixa ter literais para tipos definidos pelo usuário. Estou curioso sobre quais outras linguagens que te permitem fazer isso.

Share Comente no Twitter