代码之家  ›  专栏  ›  技术社区  ›  markasoftware

Haskell编译器如何“知道”IO无法展开?

  •  8
  • markasoftware  · 技术社区  · 6 年前

    显然,以下功能是不可能的,因为不可能永久打开IO值(忽略unsafeperformio或类似功能):

    unwrapIO :: IO String -> String
    unwrapIO (IO str) = str
    

    但是,类似的功能,如以下功能是可能的:

    unwrapJust :: Maybe String -> String
    unwrapJust (Just str) = str
    unwrapJust Nothing = "ignore this plz"
    

    我完全理解为什么2是可能的,但1不是,但我不理解为什么。我还可以自己制作不可拆解的类型吗?

    3 回复  |  直到 6 年前
        1
  •  11
  •   Li-yao Xia    6 年前

    Just Nothing 是该类型的数据构造函数 Maybe a . IO 没有可以说的数据构造函数(在GHC中,它实际上有构造函数,但它们实际上是GHC的实现细节,其他实现可能定义 输入输出 不同的)

    unwrapIO (IO str) = str 用同样的方式讲不通 unwrapMaybe (Maybe str) = str 没有道理。 输入输出 Maybe 不是数据构造函数,因此不能对它们进行模式匹配。

        2
  •  9
  •   amalloy    6 年前

    这是因为 IO 不导出。我是说,你可以认为它没有出口。

    您可以使用相同的策略防止自己的类型被打开。

    module Test (Test, test) where
    
    data Test a = MkTest a
    
    test :: a -> Test a
    test = MkTest
    

    您可以创建一个值 Test 使用 test ,但不能使用模式匹配打开它,因为 MkTest 不导出。

        3
  •  1
  •   WorldSEnder    6 年前

    我相信,虽然现有的答案大多是正确的,但有一个更深层的原因 IO 无法打开。 Conceptually , type IO a = RealWorld -> (a, RealWorld) . 输入输出 是一个函数类型(在隐藏在新类型包装器或等效机器后面的实际实现中)。

    那么,如何展开函数呢?别紧张,你就叫它!但是你要如何获得 RealWorld ?这是更真实的原语:您不能构造 现实世界 只有一个。

    一元实例当然可以通过 现实世界 作为一个国家,有点像 StateT 最后,构造的唯一实例是在程序启动时,然后在 输入输出 S.

    再次回到现实中,这又是一个谎言。你实际上可以得到一个 现实世界 你可以打电话给 IO a “提前”行动。有一个函数可以完全满足您的要求。它叫 System.IO.Unsafe.unsafePerformIO :: IO a -> a 尽管出于某种原因它在不安全的包中。

    推荐文章