QuickCheck Произвольный экземпляр для абстрактного типа данных с помощью умного конструктора - PullRequest
0 голосов
/ 04 мая 2020

Я новичок в языке, пытаюсь написать свою первую нетривиальную программу. По дороге я застрял в создании экземпляра Arbitrary. Тем не менее, я полагаю, что мой вопрос следует пунктам из-за моего общего непонимания, составляющего несколько аппликативных и монадических c типов. Следовательно, я надеюсь получить фундаментальное понимание следующего. Спасибо за вашу помощь!

Я определил тип Address и умный конструктор с проверкой отдельных полей следующим образом:

data Address = Address
    { street :: StreetName
    , streetExt :: Maybe StreetName
    , city :: CityName
    , zipCode :: ZipCode
    , country :: CC.CountryCode
    } deriving (Eq, Show)
mkAddress :: Text -> Maybe Text -> Text -> Text -> Text -> Maybe Address
mkAddress aStreet aStreetExt aCity aZipCode aCountry =
    Address <$> mkStreetName aStreet
            <*> Just (aStreetExt >>= mkStreetName)
            <*> mkCityName aCity
            <*> mkZipCode aZipCode
            <*> CC.fromMText aCountry

StreetName, CityName и ZipCode являются оболочками нового типа для Text с проверяющим интеллектуальным конструктором, который просто ограничивает максимальную длину этих полей. Поле streetExt является необязательным. Код страны использует Data.ContryCodes.CountryCode.

Общий тип является абстрактным, определяющий модуль экспортирует только интеллектуальный конструктор, но не конструктор данных.

Сейчас я пытаюсь создать произвольный экземпляр для этот тип>

instance Arbitrary D.Address where
    arbitrary = do
        maybeAddress <- D.mkAddress <$> arbitrary         -- streetName
                                    <*> return Nothing    -- streetExt
                                    <*> arbitrary         -- city
                                    <*> arbitrary         -- zipCode
                                    <*> elements ["DE", "FR", "AG", "RW"]   -- country
        return fromJust maybeAddress

Однако я застрял со следующей ошибкой проверки типов:

• Couldn't match type ‘Maybe a0 -> a0’ with ‘Gen D.Address’
      Expected type: Maybe D.Address -> Gen D.Address
      Actual type: Maybe D.Address -> Maybe a0 -> a0
• The function ‘return’ is applied to two arguments,
      but its type ‘(Maybe a0 -> a0)
                    -> Maybe D.Address -> Maybe a0 -> a0’
      has only three

Из этой ошибки я предполагаю, что существует некоторая проблема с оборачиванием Генератора внутри Maybe или наоборот. Но даже после нескольких экспериментов lift и join я не могу заставить его проверить тип. Таким образом, я подозреваю, что моя ментальная модель имеет недостатки в том, как обертываются типы и как возвращаются генераторные монады.

Было бы замечательно, если бы кто-то мог указать на мою ошибку. Кроме того, я был бы очень признателен за комментарий к этому типу моделирования данных с использованием абстрактных типов и умных конструкторов - это общая рекомендуемая практика или она приводит к проблемам, подобным той, с которой я сталкиваюсь?

Большое спасибо !

1 Ответ

1 голос
/ 04 мая 2020

В сообщении об ошибке говорится (хотя последующее объяснение вводит в заблуждение):

The function ‘return’ is applied to two arguments

У вас есть

return fromJust maybeAddress

Вы хотите

return (fromJust maybeAddress)
...