Как сделать структуру данных, которая представляет собой подмножество чисел? - PullRequest
5 голосов
/ 28 июня 2019

Мне было интересно, есть ли способ сделать что-то вроде Int типа, который может представлять только определенное подмножество чисел (например, 0 ~ 29) и заставить компилятор выдать ошибку, если вы попытаетесь сделать что-то еще с ним,

Я знаю, что могу сделать что-то вроде type MoonPhaseDay = Day1|Day2| ... |Day29, но это не масштабируется в большем диапазоне.

Я стараюсь помнить совет: «Сделайте невозможные состояния невозможными для представления».Я мог бы обойтись с Int, но мне любопытно, есть ли лучший способ.

Ответы [ 2 ]

2 голосов
/ 29 июня 2019

То, что вы ищете, иногда называют «зависимыми типами» и сегодня не является частью вяза.

Однако вы можете получить нечто подобное, создав тип в своем собственном модуле и вместо экспорта конструктора необработанного типа, только экспортируя предоставленную вами пользовательскую функцию (делая ее «Непрозрачным типом»). Таким образом, этот модуль содержит единственный код, который должен быть защищен.


Этот ответ Натана может быть полезен при изучении непрозрачных типов.

0 голосов
/ 09 июля 2019

Вы должны использовать умный конструктор.Вы реализуете свои ограничения, контролируя то, что вы экспортируете из модуля.

module Bounded exposing (Bounded, fromInt, toInt)


type Bounded
  = Bounded Int


fromInt : Int -> Maybe Bounded
fromInt n =
  if n < 0 || n > 29 then
    Nothing
  else
    Just (Bounded n)


toInt : Bounded -> Int
toInt (Bounded n) = n

Объяснение

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

Пользователи модуля могут создавать типы Bounded только с использованием fromInt.fromInt называется умным конструктором , потому что он имеет некоторую логику ( смарт ) для обеспечения соблюдения ограничений.

Если вам нужно работать с целым числом, оно переноситсяВы используете toInt.toInt гарантированно всегда возвращает целое число от 0 до 29 включительно.Нет скрытого бэкдора, который позволил бы обернуть любое другое целое число.

На HaskellWiki есть хорошая статья о умных конструкторах .

Наконец, Ричард Фельдман в своем выступлении"Типы и тесты в позолоченной розе" приведен хороший пример здесь , который точно объясняет, что вы хотите сделать.

...