Haskell: Безопасность типов с логически разными логическими значениями

Допустим, у меня есть следующий код

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не определен в IsTalls, только Bools.

Я мог бы явно извлекать 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 не должны взаимодействовать)

, но я не могу сделать это с помощью Bools (получение Бул не работает). Я даже не уверен, что это лучший подход.

7
задан Clinton 11 May 2012 в 03:19
поделиться