Что такое шаблон функционального дизайна для различного объединения с защищенным созданием и открытым доступом для чтения? - PullRequest
0 голосов
/ 29 января 2019

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

Ради аргумента предположим, что мы представляем URI со строкой, но я хочу создать тип, который имеет гарантированный проверенный URI (т. Е. Он действителен в соответствии с RFC), который также являетсястрока.Просто использование Some / None здесь не работает, так как я все еще хочу получить доступ к любой недопустимой строке.Кроме того, мне нравится мягкий рефакторинг в текущей кодовой базе (заменить существующее объединение в один случай новым объединением в один случай по многим строкам кода гораздо проще, чем в объединении с несколькими случаями).

Я могу решить эту проблему следующим образом, что, я думаю, показывает, что я собираюсь сделать (исключая случаи ошибок для простоты):

[<AutoOpen>]
module VerifiedUriModule =
    module VerifiedUri =
        type VerifiedUri = 
            private 
            | VerifiedUri of string

        let create uri = VerifiedUri uri  // validation and error cases go here

        let tryCreate uri = Some <| VerifiedUri uri  // or here

        let get (VerifiedUri uri) = uri

    let (|VerifiedUri|) x =
        VerifiedUri.get x

Дополнительный уровень с AutoOpenпросто разрешить безоговорочный доступ к использованию активного распознавателя.

Я могу в конечном итоге использовать типичный тип Result, но мне было интересно, является ли это типичной практикой кодирования, или когда я обнаруживаю, что что-то делаювот так, я должен услышать голос в своей голове, говорящий «откат, откат!», потому что я нарушаю классические принципы функционального программирования (не так ли?).

Я понимаю, что это случай сокрытия информации иэто похоже на имитацию поведения класса OO с данными.Каков будет типичный подход F # 'ish (кроме создания класса с закрытым ctor)?

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Ну, коротко: вы не скрываете свои варианты.Вы просто убедитесь, что их достаточно.И вы предоставляете функции правильных особенностей для типов карт.

Теперь более длинная версия: здесь также применима одиночная ответственность (TM).Тип конкретного соединения должен быть , предназначенный для конкретной проблемы.В вашем случае кажется разумным иметь type VerificationStamp = Verified ... | NotYetVerified | YOU_SHALL_NOT_PASS вариантов.И вы их не скрываете: для этого нет веских причин.Затем вы определяете свою verify функцию, а также другие функции, которые вы хотели бы предоставить клиентам вашего кода.Вот место, где вы держите вещи правильно: привязывая свои функции к разумным типам;Например, verify определенно будет брать string, а не один, завернутый в контейнер;но это вернуло бы VerificationStamp "myUrl".

0 голосов
/ 30 января 2019

В довольно общем смысле, я думаю, что шаблон, который вы описываете, является абстрактный тип данных - это не название для конкретной реализации F #, но оно вполне соответствует вашему описанию.

Цитировать Программирование с абстрактными типами данных Барбарой Лисков и Стивеном Зиллесом в 1974 году:

Абстрактный тип данных определяет класс абстрактных объектов, который полностью характеризуетсяоперации доступны на этих объектах.Это означает, что абстрактный тип данных может быть определен путем определения характеризующих операций для этого типа.

В вашем примере вы определяете абстрактный тип данных VerifiedUrl, который описывается тремя операциями.Операции create (или tryCreate) создают значение абстрактного типа данных, а операция get позволяет получить это значение.Операции, которые создают значение, также фиксируют тот факт, что вы можете создать VerifiedUrl только из допустимой строки URL.

Этот шаблон, возможно, несколько более сфокусирован на том факте, что вы скрываете детали реализации и выставляететолько определенные операции для манипулирования им - в то время как в вашем случае другой важный факт - то, что значения абстрактного типа данных удовлетворяют определенным свойствам - но вы можете рассматривать их как инварианты абстрактного типа данных.Я не могу придумать более надежную концепцию, чтобы уловить эту идею.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...