Curry-Howard是双重否定的通讯员((a-> r) - > r)或((a->⊥) - >⊥)?

时间:2015-05-03 00:14:46

标签: haskell continuations curry-howard

这是a双重否定的库里 - 霍华德记者; (a -> r) -> r(a -> ⊥) -> ⊥,或两者兼而有之?

这两种类型都可以在Haskell中编码如下,其中编码为forall b. b

p1 :: forall r. ((a -> r) -> r)
p2 :: (a -> (forall b. b)) -> (forall b. b)

Wadler 2003的论文以及 implementation in Haskell似乎采用前者,而有些人 其他文献(例如this)似乎支持后者。

我目前的理解是后者是正确的。我很难理解前一种风格,因为您可以使用纯计算从a创建forall r. ((a -> r) -> r)类型的值:

> let p1 = ($42) :: forall r. (Int -> r) -> r
> p1 id
42

这似乎与直觉主义逻辑相矛盾,你无法从a派生¬¬a

所以,我的问题是:p1p2都可以被视为¬¬a的Curry-Howard记者吗?如果是这样,我们如何构造p1 id :: a与直觉逻辑相互作用的事实呢?

为了便于讨论,我想出了更清晰的双重否定转换编码。感谢@ user2407038!

{-# LANGUAGE RankNTypes #-}
to_double_neg :: forall a. a -> (forall r. (a->r)->r)
to_double_neg x = ($x)

from_double_neg :: forall a. (forall r. (a->r)->r) -> a
from_double_neg x = x id

1 个答案:

答案 0 :(得分:0)

总而言之,方法p2 / T2更加自律,但我们无法从中计算出任何实际价值。另一方面,p1 / T1允许实例化r,但实例化是执行runCont :: Cont r a -> (a -> r) -> rrunContT并从中获取任何结果和副作用所必需的。

但是,我们可以在Control.Monad.Cont内模拟p2 / T2,将r实例化为Void,并仅使用副作用,如下所示:

{-# LANGUAGE RankNTypes #-}
import Control.Monad.Cont
import Control.Monad.Trans (lift)
import Control.Monad.Writer

newtype Bottom = Bottom { unleash :: forall a. a}

type C = ContT Bottom
type M = C (Writer String)

data USD1G = USD1G deriving Show

say x = lift $ tell $ x ++ "\n"

runM :: M a -> String
runM m = execWriter $
  runContT m (const $ return undefined) >> return ()
-- Are we sure that (undefined :: Bottom) above will never be used?

exmid :: M (Either USD1G (USD1G -> M Bottom))
exmid = callCC f
  where
     f k = return (Right (\x -> k (Left x)))

useTheWish :: Either USD1G (USD1G -> M Bottom) -> M ()
useTheWish e = case e of
  Left money -> say $ "I got money:" ++ show money
  Right method -> do
    say "I will pay devil the money."
    unobtainium <- method USD1G
    say $ "I am now omnipotent! The answer to everything is:"
      ++ show (unleash unobtainium :: Integer)

theStory :: String
theStory = runM $ exmid >>= useTheWish

main :: IO ()
main = putStrLn theStory

{-
> runhaskell bottom-encoding-monad.hs
I will pay devil the money.
I got money:USD1G

-}

如果我们想要进一步摆脱丑陋的undefined :: Bottom,我想我需要避免重新发明并使用CPS库,例如管道和机器。使用machines的示例如下:

{-# LANGUAGE RankNTypes, ImpredicativeTypes, ScopedTypeVariables #-}
import Data.Machine
import Data.Void
import Unsafe.Coerce

type M k a = Plan k String a
type PT k m a = PlanT k String m a

data USD = USD1G deriving (Show)

type Contract k m = Either USD (USD -> PT k m Void)

callCC :: forall a m k. ((a -> PT k m Void) -> PT k m a) -> PT k m a
callCC f = PlanT $
    \ kp ke kr kf ->
     runPlanT (f (\x -> PlanT $ \_ _ _ _ -> unsafeCoerce $kp x))
     kp ke kr kf

exmid ::  PT k m (Contract k m)
exmid = callCC f
  where
    f k =
       return $ Right (\x -> k (Left x))

planA :: Contract k m -> PT k m ()
planA e = case e of
  Left money ->
    yield $ "I got money: " ++ show money
  Right method -> do
    yield $ "I pay devil the money"
    u <- method USD1G
    yield $ "The answer to everything is :" ++ show (absurd u :: Integer)

helloMachine :: Monad m => SourceT m String
helloMachine = construct $ exmid >>= planA

main :: IO ()
main = do
  xs <- runT helloMachine
  print xs

感谢我们的对话,现在我对runPlanT的类型签名有了更好的理解。