()
является ⊤
, т.е. unit type, не ⊥
(The bottom type).Большая разница в том, что тип устройства заселен, так что она имеет значение (()
в Haskell), с другой стороны, нижний тип необитаем, так что вы не можете писать функции так:
absurd : ⊥
absurd = -- no way
Конечно, вы можете сделать это в Haskell, так как «нижний тип» (нет такой вещи, конечно) здесь заселен undefined
. Это делает Haskell непоследовательным.
функции, как это:
disprove : a → ⊥
disprove x = -- ...
могут быть записаны, это то же самое, как
disprove : ¬ a
disprove x = -- ...
т.е. он опровергая тип a
, так что a
абсурдная.
В любом случае, вы можете увидеть, как тип блока используется на разных языках, а () ::()
в Haskell, () : unit
в ML, () : Unit
в Scala и tt : ⊤
в Agda. В таких языках, как Haskell и Agda (с модой IO), такие функции, как putStrLn
, должны иметь тип String → IO ⊤
, а не String → IO ⊥
, так как это абсурд (логически он утверждает, что нет строк, которые можно распечатать, это просто неправильно).
ОТКАЗ: предыдущий текст использовать Agda обозначения и больше о Agda чем Haskell.
В Haskell, если мы имеем
data Void
Это не означает, что Void
необитаем. В нем проживает undefined
, не заканчивающиеся программы, ошибки и исключения. Например:
data Void
instance Show Void where
show _ = "Void"
data Identity a = Identity { runIdentity :: a }
mapM__ :: (a -> Identity b) -> [a] -> Identity Void
mapM__ _ _ = Identity undefined
затем
print $ runIdentity $ mapM__ (const $ Identity 0) [1, 2, 3]
--^will print "Void".
case runIdentity $ mapM__ (const $ Identity 0) [1, 2, 3] of _ -> print "1"
--^will print "1".
let x = runIdentity $ mapM__ (const $ Identity 0) [1, 2, 3]
x `seq` print x
--^will thrown an exception.
Но это также не означает, что Void
является ⊥. Так
mapM_ :: Monad m => (a -> m b) -> [a] -> m Void
где Void
является decalred, как пустой тип данных, это нормально. Но
mapM_ :: Monad m => (a -> m b) -> [a] -> m ⊥
это бессмыслица, но нет такого типа, как ⊥ в Haskell.
Для большинства повседневных программ Haskell нам нравится притворяться, что нет такой вещи, как '_ | _' ... мы только вытаскиваем ее, когда в более формальном режиме. То есть нам нравится притворяться, что «данные Foo = A | B' имеет только два возможных значения вместо трех; поэтому существует только одно значение типа '()'. Вы можете, если хотите, использовать термин «полностью определенный». – luqui
Какая альтернатива будет? т. е. какой разумный тип для 'writeFile' или' mapM_'? – huon
@dbaupp: 'writeFile :: FilePath -> String -> a',' mapM_ :: (Monad m) => (a -> mb) -> [a] -> mz' –