Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type Matching in Haskell

If SomeType is defined as:

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

and I will update an arbitrary X, dependent of his type as follows:

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

The third and the fourth line do the very same, they update the string in the given type. Is there any way replace these two lines by a single one, eg. by assigning the type to a variable?

like image 862
ChrisQuignon Avatar asked Nov 28 '22 08:11

ChrisQuignon


2 Answers

Not by assigning the type to a variable, but by doing field replacement:

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

This returns the same st as its argument, but with the value of the myString field replaced. It's one of the nice features of fields that you can do this without caring which data constructor it is, as long as it's one of the data constructors that uses myString.

like image 186
Dan Avatar answered Dec 05 '22 02:12

Dan


You can use Scrap-Your-Boilerplate for this.

{-# 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"))

This changeST changes every internal String in your structure to "newString" and every Bool to True.

like image 40
yairchu Avatar answered Dec 05 '22 02:12

yairchu