Как изменить / извлечь значение части определенного вручную типа данных? - PullRequest
1 голос
/ 20 марта 2020

Скажем, у меня есть следующий тип данных:

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

Что я могу использовать вместо function с таким, чтобы instance2 = Element1 (Just 2)?

Ответы [ 3 ]

4 голосов
/ 20 марта 2020

Вы даете три уравнения:

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

Давайте использовать эти уравнения для решения для function.

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

Эта последняя строка:

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

это очень хороший кусок кода Haskell, который определяет функцию с именем function. Конечно, здесь не говорится, что делать с вещами, которые на самом деле Element2 с, или Element1 с, содержащими Nothing с, или Element1 с, содержащими Just с, содержащими вещи, которые не 't 1! Но он соответствует спецификации, данной тремя исходными уравнениями, и я думаю, что это отличная демонстрация концепции «эквационального мышления», которую Haskell разделяет с математикой.

3 голосов
/ 20 марта 2020

Если вы немного обобщите свой тип, вы можете сделать его функтором:

{-# LANGUAGE DeriveFunctor #-}
data MyType <b>a</b> = Element1 (Maybe <b>a</b>) | Element2 (Maybe <b>a</b>) <b>deriving (Functor, Show)</b>

Тогда вам нужна функция (<$) из класса типов Functor.

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

Если вы не хотите использовать расширение DeriveFunctor, экземпляр тривиально определить вручную.

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

Специализированная версия (<$) для Тип monomorphi c может выглядеть как

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)

Или вы можете определить свой тип как продукт, чтобы обобщить функцию над конструкторами данных.

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

change :: Int -> MyType -> MyType
change new (MyType tag old) = MyType tag (new <$ old)
1 голос
/ 20 марта 2020

Вы можете определить свой тип данных, используя синтаксис записи:

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