Powiedzmy mam następujący kodHaskell: bezpieczeństwo Type z logicznie różnych wartościach logicznych
type IsTall = Bool
type IsAlive = Bool
is_short_alive_person is_tall is_alive = (not is_tall) && is_alive
Say, później, mam następujący
a :: IsAlive
a = False
b :: IsTall
b = True
i wywołać następujący , coraz dwa argumenty wokół niewłaściwy sposób:
is_short_alive_person a b
Ten powodzeniem opracowuje niestety, i przy starcie wysokich martwych ludzi zamiast tego znajdują się zamiast krótkich, żywych ludzi.
Chciałbym, aby powyższy przykład się nie kompilował.
Moja pierwsza próba była:
newtype IsAlive = IsAlive Bool
newtype IsTall = IsTall Bool
Ale wtedy nie można zrobić coś takiego.
switch_height :: IsTall -> IsTall
switch_height h = not h
jako not
nie jest zdefiniowana w IsTall
s wówczas Bool
s.
Mogłem jawnie wyodrębnić Bool
s przez cały czas, ale to w dużej mierze pokonało cel.
Zasadniczo chcę IsTall
s do interakcji z innymi IsTall
s, podobnie jak oni Bool
s, z wyjątkiem, że nie będą korzystać z Bool
s oraz IsAlive
s bez wyraźnego obsady.
Jaki jest najlepszy sposób, aby to osiągnąć.
p.s. Myślę, że osiągnięto to z liczbami, wykonując w GHC:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype UserID = UserID Int deriving (Eq, Ord, Num)
newtype GroupID = GroupID Int deriving (Eq, Ord, Num)
(tj identyfikatora użytkownika i GroupID nie powinny wchodzić w interakcje)
ale nie wydaje się to zrobić z Bool
s (wynikające Bool nie działa). Nie jestem nawet pewien, czy powyższe jest najlepszym podejściem.
Pożądane typy "IsTall" i "IsAlive" to straszny pomysł. Jest to fałszywe uogólnienie zwykle przyzwoitej idei używania typów rozłącznych w celu zapewnienia bezpieczeństwa typu. Porównaj to ze swoim 'UserID' i' GroupID'; w takim przypadku sensowne jest posiadanie oddzielnych typów, ponieważ nie ma sensu przekazywać "UserId", gdzie "GroupID" jest potrzebny, lub dodawać jeden do drugiego (chociaż prawdopodobnie nie powinno też implementować 'Num'). Jednak sensowne jest sprawdzenie, czy dana osoba jest wysoka * i * żywa, wysoka * lub * żywa, * nie * wysoka * i * żywa itd. –
sacundim: W dużym stopniu zmieniłem zdanie na ten punkt widok. Skończyło się na użyciu takich rzeczy jak 'newtype Height = Tall | Short', a następnie robi 'x == Tall' itd. Trochę więcej pisania, ale pomyślałem, że sprawiłoby, że kod byłby bardziej czytelny i bezpieczniejszy. – Clinton