Допустим, у меня есть следующий код
type IsTall = Bool
type IsAlive = Bool
is_short_alive_person is_tall is_alive = (not is_tall) && is_alive
Скажем, позже , у меня есть следующее
a :: IsAlive
a = False
b :: IsTall
b = True
И вызовите следующее, перепутав два аргумента:
is_short_alive_person a b
Это успешно компилируется, к сожалению, и во время выполнения вместо низкорослых живых людей обнаруживаются высокие мертвые люди.
Я бы хотел, чтобы приведенный выше пример не компилировался.
Моя первая попытка была:
newtype IsAlive = IsAlive Bool
newtype IsTall = IsTall Bool
Но тогда я не могу сделать что-то вроде.
switch_height :: IsTall -> IsTall
switch_height h = not h
Поскольку not
не определен в IsTall
s, только Bool
s.
Я мог бы явно извлекать Bool
все время, но это в значительной степени противоречит цели.
По сути, я хочу, чтобы IsTall
взаимодействовали с другими IsTall
, точно так же, как они Bool
, за исключением того, что они не будут взаимодействовать с Bool
и IsAlive
без явного приведения.
Как лучше всего это сделать.
п.с.Я думаю, что добился этого с числами, выполнив в GHC:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype UserID = UserID Int deriving (Eq, Ord, Num)
newtype GroupID = GroupID Int deriving (Eq, Ord, Num)
(т.е. UserID и GroupID не должны взаимодействовать)
, но я не могу сделать это с помощью Bool
s (получение Бул не работает). Я даже не уверен, что это лучший подход.