Pergunta

Se SomeType é definido como:

data SomeType = X {myBool :: Bool} 
                | Y {myString :: String} 
                | Z {myString :: String}

e vou atualizar um arbitrário X, dependente de seu tipo, como segue:

changeST :: SomeType -> SomeType
changeST (X b) = (X True)
changeST (Y s) = (Y "newString")
changeST (Z s) = (Z "newString")

A terceira e a quarta linha de fazer o mesmo, eles atualizam a seqüência de caracteres de um dado tipo.Existe alguma maneira de substituir essas duas linhas em um único arquivo, por exemplo.atribuindo-se o tipo de uma variável?

Foi útil?

Solução

Não, atribuindo-se o tipo de uma variável, mas fazendo a substituição de campo:

changeST :: SomeType -> SomeType
changeST (X b) = (X True)
changeST st = st { myString = "newString" }

Isso retorna o mesmo ponto como seu argumento, mas com o valor da myString campo substituído.É um dos bons recursos de campos que você pode fazer isso sem se importar com que os dados construtor é, como um dos dados de construtores que usa myString.

Outras dicas

Você pode usar Scrap Your-Boilerplate por esta.

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Generics

data SomeType
  = X { myBool :: Bool }
  | Y { myString :: String }
  | Z { myString :: String }
  deriving (Data, Typeable)

changeST :: SomeType -> SomeType
changeST = everywhere (mkT (const True)) . everywhere (mkT (const "newString"))

este changeST muda cada interno String em sua estrutura para "newString" e todo Bool para True.

Eu prefiro a solução de Dan, mas os guardas de padrões no GHC (padrão em Haskell 2010) são uma alternativa legal à proposta de Michael:

{-# LANGUAGE PatternGuards #-}
changeST :: SomeType -> SomeType
changeST x | X _ <- x = X True
           | Y _ <- x = Y newString
           | Z _ <- x = Z newString
  where    newString = "newString"

Suas três definições de changeST são separados um do outro, então a resposta curta é "não". No entanto, existem pelo menos duas maneiras de fazer isso.

Padrão corresponde a ambos Y e Z Construtores de uma só vez:

Você pode combinar a 2ª e a 3ª definição, tornando seu padrão correspondente mais geral:

changeST x = x { myString = "newString"}

Isso cria uma nova versão de x, seja um Y ou a Z, substituindo o membro da string. Você tem que ter cuidado ao fazer isso, no entanto. Se você renomear mais tarde o campo de string de Z, por exemplo, você receberá falhas de correspondência de padrões de tempo de execução ao chamar Changest com um Z argumento.

Use uma expressão de caso:

Se você combinar suas três definições em uma, poderá compartilhar dados entre eles.

changeST :: SomeType -> SomeType
changeST x = case x of
    X _ -> X True
    Y _ -> Y newString
    Z _ -> Z newString
  where
    newString = "newString"
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top