Chciałbym móc tworzyć instancje IsString
przy użyciu rozszerzenia GHC OverloadedStrings
tak, że moja instancja odrzuca niektóre literały jako nieważne i takie, że odrzucenie ma miejsce podczas kompilacji, więc błędy programowania nie wchodzą w kod I dać moim użytkownikom.Jak mogę sprawdzić poprawność literałów podczas kompilacji w instancjach IsString?
Mam kilka przypadków użycia, w których mam typ Name
, który dopuszcza tylko niektóre ciągi. na przykład
module Name (Name(getName), makeName) where
import Data.Text (Text)
import qualified Data.Text as Text
-- | A guaranteed non-empty name.
newtype Name = Name { getName :: Text } deriving (Eq, Show, Ord)
makeName :: Text -> Maybe Name
makeName name
| Text.null name = Nothing
| otherwise = Just name
W prawdziwym przypadku użyłbym sprawdzenia poprawnych znaków, nie zaczynając od cyfry, tego rodzaju rzeczy.
Chodzi o to, że nie eksportujemy konstruktora Name
, co oznacza, że każdy, kto używa wartości Name
, może ufać, że ma określone właściwości (w tym przypadku niepuste).
Moim problemem jest to, że chciałbym używać dosłownych nazw w wielu miejscach. na przykład
programName :: Name
programName = fromJust $ makeName "the-great-and-powerful-turtle"
Ponieważ robię to dużo, ja zdefiniował unsafeMakeName
pomocnika, który ma prawie to samo:
unsafeMakeName :: Text -> Name
unsafeMakeName name = fromMaybe (error $ "Invalid name: " <> Text.unpack name) (makeName name)
Problem z tego podejścia jest to, że mimo, że przyczyną błędu jest błędem programistycznym, nie dowiedziałem się o tym do czasu uruchomienia.
Co chcę zrobić, to napisać instancję IsString
dla Name
, która wykonuje to sprawdzenie, np.
instance IsString Name where
fromString = unsafeMakeName . Text.pack
... ale aby uzyskać błąd dotyczący nieprawidłowych nazw w literałach podczas kompilacji.
Gdy próbuję tego, wydaje mi się, że błędy występują tylko w czasie wykonywania, gdy używana jest wartość literału. Jest to mniej niż idealne, ponieważ jest to błąd w moim rzeczywistym kodzie.
Czy mogę to zrobić? Czy jest to coś, co można naprawić w GHC? Zauważ, że już tam jest filed a bug.
Myślę, że jedynym sposobem, aby to zrobić, byłoby użycie szablonu Haskella do sprawdzania poprawności poprzez łączenie w czasie kompilacji. –
Dla czegoś ciężkiego, możesz spróbować użyć sprawdzania pełnej płynności-haskell.Przynajmniej byłoby fajnie. –
Byłoby świetnie na przykład dla 'printf' i jego łańcucha formatującego. – chi