1
votes

Comment changer / extraire la valeur d'une partie d'un type de données défini manuellement?

Disons que j'ai le type de données suivant:

data MyType = Element1 (Maybe Int) | Element2 (Maybe Int)
instance1 = Element1 (Just 1)
instance2 = function(instance1)

Que puis-je utiliser à la place de function avec pour que instance2 = Element1 (Just 2) ?


4 commentaires

Vous ne pouvez pas manipuler un objet. Toutes les valeurs sont immuables . Vous pouvez construire un nouvel objet, c'est-à-dire une copie modifiée de l'original.


Ce que vous voulez faire n'est cependant pas tout à fait clair. Qu'est-ce que c'est un Element2 Nothing ? Ou un Element1 (Just 3) ?


@WillemVanOnsem J'ai édité la question pour refléter l'immuabilité d'un objet et clarifier ma question.


Vous utilisez correspondance de modèles


3 Réponses :


3
votes

Si vous générez légèrement votre type, vous pouvez en faire un foncteur:

data MyTypeTags = Element1 | Element2
data MyType = MyType MyTypeTags (Maybe Int)

change :: Int -> MyType -> MyType
change new (MyType tag old) = MyType tag (new <$ old)

Ensuite, la fonction que vous recherchez est (, du Functor typeclass.

data MyType = Element1 (Maybe Int) | Element2 (Maybe Int)

change :: Int -> MyType -> MyType
change new (Element1 old) = Element1 (new <$ old)
change new (Element2 old) = Element2 (new <$ old)

Si vous ne souhaitez pas utiliser l'extension DeriveFunctor , l'instance est trivial à définir manuellement.

instance Functor MyType where
    fmap f (Element1 x) = Element1 (fmap f x)
    fmap f (Element2 x) = Element2 (fmap f x)

Une version spécialisée de ( pour un type monomorphe pourrait ressembler à

XXX

Ou, vous pouvez définir votre type en tant que produit, pour généraliser la fonction sur les constructeurs de données.

> i1 = Element1 (Just 1)
> i1
Element1 (Just 1)
> 2 <$ i1
Element1 (Just 2)


2 commentaires

Merci. Cependant, si, par exemple, a devait avoir le type Int , y a-t-il un moyen de contourner ce problème?


Vous pouvez envisager d'utiliser la classe MonoFunctor de la bibliothèque mono-traversible . Sinon, je pense que vous auriez juste besoin d'écrire votre propre fonction change :: Int -> MyType -> MyType , similaire à (<$) , à la main.



4
votes

Vous donnez trois équations:

function (Element1 (Just 1)) = Element1 (Just 2)

Utilisons ces équations pour résoudre la fonction.

function (instance1) = instance2
function (Element1 (Just 1)) = instance2
function (Element1 (Just 1)) = Element1 (Just 2)

Cette dernière ligne:

instance1 = Element1 (Just 1)
instance2 = function(instance1)
instance2 = Element1 (Just 2)

est un très bon morceau de code Haskell qui définit une fonction nommée function . Bien sûr, il ne dit pas quoi faire des choses qui sont en fait des Element2 , ou qui sont des Element1 contenant des Nothing , ou qui sont des Element1 contenant des Just s contenant des choses qui ne sont pas 1 ! Mais cela répond aux spécifications données par les trois équations originales, et je pense que c'est une excellente démonstration du concept de «raisonnement équationnel» que Haskell partage avec les mathématiques.


0 commentaires

1
votes

Vous pouvez définir votre type de données en utilisant la syntaxe d'enregistrement:

data MyType = Element1 { x :: (Maybe Int) } | Element2 { x :: (Maybe Int)}
instance1 = Element1 (Just 1)
instance2 = instance1 { x = Just 2 }


0 commentaires