在where子句下做声明

时间:2018-06-11 18:51:32

标签: haskell scope functional-programming monads do-notation

我尝试使用 IO [String] 绑定将 [String] 转换为<-;但是,我需要使用do块在where语句下执行此操作,但Haskell一直抱怨缩进。这是代码:

decompEventBlocks :: IO [String] -> IO [[String]]
decompEventBlocks words
 | words' /= [] = block : (decompEventBlocks . drop $ (length block) words')
 | otherwise = []
  where 
   do
    words' <- words
    let block = (takeWhile (/="END") words')

这是什么原因?我们如何在 do 声明中使用 where 块?此外,我们是否有机会在警卫面前发表一些声明?

4 个答案:

答案 0 :(得分:5)

您无法转换为IO字符串

然而,您可以做的是将IO String的内容绑定到'变量',但这仍然会导致整个计算嵌入到IO中。

try
{
    var host = BuildWebHost(args);

    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<myContext>();
            DbInitializer.Seed(context);
        }
        catch
        {
            throw;
        }
    }

    host.Run();
}
catch
{
    throw;
}

回答你的问题

foo = do
   x <- baz -- here baz is the IO String
   let x' = doStuff x
   return x' -- embeds the String inside IO, as otherwise the computation would result in IO ()

答案 1 :(得分:4)

请记住:do - 对于monadic表示法,块为syntactic sugar。这意味着以下情况适用:

do {a; b} = a >> b
dp {a <- b; c} = b >>= \a -> c

换句话说,当使用do - 表示法时,实际上是在生成值。这就是为什么你不能在do语句的顶层有一个where块。

解决这个问题的方法是将函数放入do - 块:

decompEventBlocks :: IO [String] -> IO [[String]]
decompEventBlocks words = do
    -- We unwrap the IO [String], but we keep it in the do-block,
    -- because it must be kept in a monadic context!
    words' <- words 
    let block = (takeWhile (/="END") words')
    -- This is equivalent to the guards you had in your function.
    -- NB return :: Monad m => a -> m a, to keep it in a monadic context!
    if not $ null words'
        then do 
          -- Since the recursion is monadic, we must bind it too:
          rest <- decompEventBlocks $ return $ drop (length block) words'
          return $ block : rest
        else return []

要了解monad,do - 符号,>>=>>,我强烈推荐阅读the LYAH chapters,以便在尝试更多monadic代码之前获得良好的理解。< / p>

答案 2 :(得分:0)

作为AJFarmar答案的一个略微不同的角度:Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Person is not mapped [select p from Person p] at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:131) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162) at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:662) at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:678) at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:23) at models.JPAPersonRepository.list(JPAPersonRepository.java:48) at models.JPAPersonRepository.lambda$null$2(JPAPersonRepository.java:35) at play.db.jpa.DefaultJPAApi.withTransaction(DefaultJPAApi.java:142) at play.db.jpa.DefaultJPAApi.withTransaction(DefaultJPAApi.java:100) Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Person is not mapped [select p from Person p] at org.hibernate.hql.internal.ast.QuerySyntaxException.generateQueryException(QuerySyntaxException.java:79) at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:218) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:142) at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115) at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:77) at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:153) at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:545) at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:654) at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:678) 中唯一的东西就是声明。 func switchCameraTapped() { //Change camera source //Indicate that some changes will be made to the session session.beginConfiguration() //Remove existing input guard let currentCameraInput: AVCaptureInput = session.inputs.first else { return } //Get new input var newCamera: AVCaptureDevice! = nil if let input = currentCameraInput as? AVCaptureDeviceInput { if (input.device.position == .back) { newCamera = cameraWithPosition(position: .front) } else { newCamera = cameraWithPosition(position: .back) } } //Add input to session var err: NSError? var newVideoInput: AVCaptureDeviceInput! do { newVideoInput = try AVCaptureDeviceInput(device: newCamera) } catch let err1 as NSError { err = err1 newVideoInput = nil } if let inputs = session.inputs as? [AVCaptureDeviceInput] { for input in inputs { session.removeInput(input) } } if newVideoInput == nil || err != nil { print("Error creating capture device input: \(err?.localizedDescription)") } else { session.addInput(newVideoInput) } //Commit all the configuration changes at once session.commitConfiguration() } // Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found func cameraWithPosition(position: AVCaptureDevice.Position) -> AVCaptureDevice? { let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified) for device in discoverySession.devices { if device.position == position { return device } } return nil } 块不是声明,它们是表达式。即这与您尝试编写where时的情况相同。如果您想在do中声明where 2+5,则必须

block

答案 3 :(得分:0)

使用表示法来编写一般表格的表达式

ex :: Monad m => m t
let ex = do 
          {  x <- foo         -- foo        :: Monad m => m a,   x :: a
          ;  y <- bar x       -- bar  x     :: Monad m => m b,   y :: b
          ;  z <- baz x y     -- baz  x y   :: Monad m => m c,   z :: c
          ;  quux x y z       -- quux x y z :: Monad m => m t
          }

请注意,所有m都相同,而abc,...可能会有所不同,尽管t位于最后执行子表达式的类型和整体 do 表达式的类型是相同的。

do 符号变量被称为&#34;绑定&#34;由<-构造。它们在引入时(<-的左侧)进入范围,并保留在所有后续 do 子表达式的范围内。

可用于任何monad的一个内置monadic表达式为return :: Monad m => a -> m a。因此x <- return v x绑定到v,以便x在后​​续子表达式中可用,并且值为{ {1}}。

所有执行变量限制 v 块,而不能在它外面使用。每个变量的范围都是同一do块中的所有代码,位于变量绑定之下/之后。

这也意味着do是非递归绑定,因为变量不能在右侧和左侧:它将是两个在这种情况下,具有相同名称的不同变量,并且必须在该点之上的某处建立右侧的变量。

这里有一些一般模式:

<-

所有do { _ <- p ; _ <- q ; r } === do { p ; q ; r } do { x <- p ; return x } === do { p } === p do { x <- return v ; foo x } === do { foo v } === foo v do { p ; q ; r } === do { p ; do { q ; r } } === do { do { p ; q } ; r } do { x <- p ; === do { x <- p ; y <- q x ; z <- do { y <- q x ; return (foo x y) } return (foo x y) } ; return z } 表达式只是表达式,因此表达式尤其可以是Monad m => m a表达式,其结果和备用分支具有相同的monadic类型(这通常令人困惑)初学者):

if - then - else

更新: monad的一个要点是它与纯计算的完全分离效果。一旦进入 monad,您就无法&#34;离开&#34; 。 Monadic计算可以使用纯计算,但反之亦然。