Haskell 编写简单的快速检查URL生成器时出现嵌套单子问题
另一个新手问题可能是因为我没有掌握Haskell中的MonadicHaskell 编写简单的快速检查URL生成器时出现嵌套单子问题,haskell,uri,monads,quickcheck,do-notation,Haskell,Uri,Monads,Quickcheck,Do Notation,另一个新手问题可能是因为我没有掌握Haskell中的Monadicdo:我想使用modern URI包中的Text.URI类型为格式良好的URI编写一个简单的快速检查生成器。据我所知,这里涉及两种类型的monad:MonadThrow用于URI构造时的错误处理,以及来自QuickCheck的Gen 下面是我实现生成器的尝试。它不进行类型检查: import qualified Text.URI as URI uriGen :: Gen URI.URI uriGen = do sc &l
do
:我想使用modern URI
包中的Text.URI
类型为格式良好的URI编写一个简单的快速检查生成器。据我所知,这里涉及两种类型的monad:MonadThrow
用于URI构造时的错误处理,以及来自QuickCheck的Gen
下面是我实现生成器的尝试。它不进行类型检查:
import qualified Text.URI as URI
uriGen :: Gen URI.URI
uriGen = do
sc <- elements ["https", "http", "ftps", "ftp"]
tld <- elements [".com", ".org", ".edu"]
hostName <- nonEmptySafeTextGen -- (:: Gen Text), a simple generator for printable text.
uri <- do
scheme <- URI.mkScheme sc
host <- URI.mkHost $ (hostName <> "." <> tld)
return $ URI.URI (Just scheme) (Right (URI.Authority Nothing host Nothing)) Nothing [] Nothing
return uri
从这个错误中,我怀疑我关于打开和包装URI片段的直觉是错误的。我哪里会犯错?什么是正确的直觉
非常感谢你的帮助 最简单的解决方案是将单子相互嵌套,例如:
——MonadThrow的一个实例是Maybe,因此这是一个可能的类型签名
--uriGen::Gen(可能是URI.URI)
uriGen::MonadThrow m=>Gen(muri.URI)
尿素=do
sc Gen b
与上面的类型匹配:uriGen::Gen(可能是URI.URI)
编辑:在评论中回答您的问题:
MonadThrow
是一个类型类,它是Monad
的超类(请参阅)。你写的相当于
uriGen::Gen URI.URI
尿素=do
sc也许您可以使用这样的映射
和MonadThrow
实例来描述也许
一个重要的细节:您希望程序在失败时做什么?它应该重试直到您得到一个有效的URI,还是应该返回一个指示失败的值?非常感谢您的帮助。我的理解是:除了故障时该怎么办这个问题之外,我的类型错误是因为我使用了url
的一元绑定,而不是let
绑定?因为外部单子是Gen
而不是MonadThrow
,所以单子绑定不会进行类型检查?@UlrichSchuster我现在更新了我的答案。这说明了吗?是的,你基本上是对的。唯一的细节是,MonadThrow
不仅仅是一个Monad
,而是一类Monad,其中包括可能
,或者
或者
和IO
,但不是Gen
@UlrichSchuster如果你看看如何做
-符号desugars,它可能会帮助你直觉地了解为什么它是等价的:
• No instance for (MonadThrow Gen)
arising from a use of ‘URI.mkScheme’
• In a stmt of a 'do' block: scheme <- URI.mkScheme sc
In a stmt of a 'do' block:
uri <- do scheme <- URI.mkScheme sc
host <- URI.mkHost $ (hostName <> "." <> tld)
return
$ URI.URI
(Just scheme)
(Right (URI.Authority Nothing host Nothing))
Nothing
[]
Nothing
Prelude Test.QuickCheck> :i Gen
newtype Gen a
= Test.QuickCheck.Gen.MkGen {Test.QuickCheck.Gen.unGen :: Test.QuickCheck.Random.QCGen
-> Int -> a}
-- Defined in ‘Test.QuickCheck.Gen’
instance [safe] Applicative Gen -- Defined in ‘Test.QuickCheck.Gen’
instance [safe] Functor Gen -- Defined in ‘Test.QuickCheck.Gen’
instance [safe] Monad Gen -- Defined in ‘Test.QuickCheck.Gen’
instance [safe] Testable prop => Testable (Gen prop)
-- Defined in ‘Test.QuickCheck.Property’