【问题标题】:How to combine Arbitrary and IO monads?如何结合任意和 IO 单子?
【发布时间】:2017-12-06 00:29:48
【问题描述】:

我正在尝试编写一个程序,该程序将Arbitrary 实例生成的数据列表写入文件,但我在组合ArbitraryIO monad 时遇到了麻烦。

我正在尝试做的简化版本如下所示。

main = do
  let n = 10
  list <- vector n
  writeFile "output.txt" (unlines $ show <$> list)

这会导致类型错误,因为 writeFileIO monad 与 vectorGen monad 不匹配。

TestCases.hs:31:3: error:
    • Couldn't match type ‘IO’ with ‘Test.QuickCheck.Gen.Gen’
      Expected type: Test.QuickCheck.Gen.Gen ()
        Actual type: IO ()
    • In a stmt of a 'do' block:
        writeFile "output.txt" (unlines $ show <$> list)
      In the expression:
        do { let n = 10;
             list <- vector n;
             writeFile "output.txt" (unlines $ show <$> list) }
      In an equation for ‘main’:
          main
            = do { let n = ...;
                   list <- vector n;
                   writeFile "output.txt" (unlines $ show <$> list) }

我曾尝试使用liftIO 来解决这种类型不匹配的问题,但由于Gen 缺少MonadIO 实例,这似乎不起作用。

main = do
  let n = 10
  list <- vector n :: Gen [Integer]
  liftIO $ writeFile "output.txt" (unlines $ show <$> list)

给出错误

TestCases.hs:32:3: error:
    • No instance for (MonadIO Gen) arising from a use of ‘liftIO’
    • In a stmt of a 'do' block:
        liftIO $ writeFile "output.txt" (unlines $ show <$> list)
      In the expression:
        do { let n = 10;
             list <- vector n :: Gen [Integer];
             liftIO $ writeFile "output.txt" (unlines $ show <$> list) }
      In an equation for ‘main’:
          main
            = do { let n = ...;
                   list <- vector n :: Gen [Integer];
                   liftIO $ writeFile "output.txt" (unlines $ show <$> list) }

如何将任意生成的列表打印到文件中?

【问题讨论】:

    标签: haskell monads quickcheck


    【解决方案1】:

    正如Test.QuickCheck.Gen 告诉你的那样,你可以使用QuickCheck-GenT 中的GenTGenT mMonadIO 实例,只要 m 是。

    main = join . generate . runGenT $ do
      let n = 10
      list <- liftGen $ vector n
      liftIO $ writeFile "output.txt" (unlines $ show <$> list)
    

    似乎可行。

    【讨论】:

      【解决方案2】:

      vector 函数为您提供列表生成器,而不是特定列表:

      vector :: Arbitrary a => Int -> Gen [a]
      

      因为(&gt;&gt;=) :: Monad m =&gt; m a -&gt; (a -&gt; m b) -&gt; m b,它不会让你离开Gen。但是generate 来自Test.QuickCheck.Gen 的特定值生成适合这种情况:generate :: Gen a -&gt; IO a。所以generate (vector n) &gt;&gt;= writeFile "output.txt" . unlines . map show 应该做你想做的事(除了类型歧义:在你的例子中不清楚Gen [a] 你的向量会产生什么,所以也许添加类似(vector n :: Gen [Int]) 的东西,除非你的实际应用程序为类型提供了足够的上下文推理。

      【讨论】:

        猜你喜欢
        • 2016-08-29
        • 1970-01-01
        • 1970-01-01
        • 2021-11-22
        • 2018-06-24
        • 1970-01-01
        • 1970-01-01
        • 2017-11-18
        • 1970-01-01
        相关资源
        最近更新 更多