【问题标题】:Nested "where" or "let in" CodeStyle in Haskell [closed]Haskell中嵌套的“where”或“let in”CodeStyle [关闭]
【发布时间】:2021-12-28 23:57:05
【问题描述】:

我在 Haskell 中遇到了一些问题:代码风格和大函数(我将继续通过编写玩具语言来学习 Haskell)。

我有一些必要的大功能(参见示例)。其中有两个子功能(嵌套在哪里)。并且没有理由将其子功能放在模块 scope 中。 “Haskell code-style”或“Haskell code-style best practics”如何解决这个“不优雅和笨拙的代码”问题?

功能(后面有评论):

-- We can delete (on DCE) any useless opers.
-- Useful opers - only opers, whitch determine (directly or transitivery) result of GlobalUse oper
addGlobalUsageStop :: [Var] -> IR -> IR
addGlobalUsageStop guses iR = set iOpers (ios ++ ios') $ set opN opn' iR
    where
    ios = _iOpers iR
    gdefs = _gDefs iR :: M.Map Int Var
    opn = _opN iR
    guses' = nub $ filter isRegGlobal guses
    ogs = catMaybes $ map (concatIOperWithGDef gdefs) $ reverse ios
        where
        concatIOperWithGDef gdefs' (i, o) = case gdefs' M.!? i of
            Nothing -> Nothing
            Just gd -> Just (o, gd)
    nops = newGUses ogs guses'
        where
        newGUses [] _ = []
        newGUses _ [] = []
        newGUses ((Oper _ d _ _, g):os) guses = if elem g guses
            then (Oper GlobalUse g (RVar d) None):newGUses os (filter (g /=) guses)
            else newGUses os guses
    ios' = zip [opn..] nops
    opn' = opn + length ios'  

注意事项:

  1. 如果你想知道我为什么要写这么大的函数,答案是: 因为这是一些大的(编译器中需要的功能): - 对于每个“返回变量”,我们应该找到最后一个操作,女巫定义它(实际上是对应的虚拟寄存器),并用构造的操作扩展我们的 IR。

  2. 我见过一些类似的问题:Haskell nested where clause and "let ... in" syntax 但它们是关于“如何打字正确的代码?”,而我的问题是“这个代码代码样式是否正确,如果不是 - 我该怎么办?”。

【问题讨论】:

    标签: haskell compiler-construction


    【解决方案1】:

    并且没有理由将其子功能放在模块范围内

    反过来想。是否有任何理由将子功能放在本地范围内?然后去做。这可能是因为

    1. 它需要访问本地绑定的变量。在这种情况下,它必须是本地的,否则你需要额外的参数。
    2. 它做了一些非常明显且仅与特定用例相关的事情。这可能是一些操作的单行定义,您不关心考虑一个正确的描述性名称,或者它可能是一个 go 助手,基本上完成了封闭函数的全部工作。

    如果这些都不适用,并且您可以给本地函数一个描述性的名称(正如您已经完成的那样),然后将它放在模块范围内。添加类型签名,使其更清晰。不要从模块中导出它。

    将函数置于模块范围内也无需像使用gdefs' 那样重命名变量。这是导致 Haskell 代码错误的更常见原因之一。

    【讨论】:

    • >> 将函数放在模块范围内也无需像使用 gdefs' 那样重命名变量。这是导致 Haskell 代码中错误的更常见原因之一。 -- ===================== 感谢您对这个问题的额外关注。它已经引起了错误。
    【解决方案2】:

    这个问题很好,但示例代码不是一个很好的例子。对我来说,在这种特殊情况下的正确解决方法是不要谈论如何时尚地嵌套wheres;它是谈论如何使用库函数和语言特性来简化代码,以至于你首先不需要where。特别是,列表推导可以让你走得很远。以下是我将如何编写这两个定义:

    import Data.Containers.ListUtils (nubOrdOn)
    
    ... where
        ogs = [(o, gd) | (i, o) <- reverse ios, Just gd <- [gdefs M.!? i]]
        nops = nubOrdOn fun
            [ Oper GlobalUse g (RVar d) None
            | (Oper _ d _ _, g) <- ogs
            , g `elem` guses'
            ]
        fun (Oper _ g _ _) = g -- this seems useful enough to put at the global scope; it may even already exist there
    

    由于ogs 没有在代码中的其他任何地方提及,您可以考虑内联它:

        -- delete the definition of ogs
        nops = nubOrdOn fun
            [ Oper GlobalUse g (RVar d) None
            | (i, Oper _ d _ _) <- reverse ios
            , Just g <- [gdefs M.!? i]
            , g `elem` guses'
            ]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-18
      • 2012-04-26
      • 2012-10-15
      • 1970-01-01
      • 2015-11-17
      • 1970-01-01
      • 1970-01-01
      • 2012-04-28
      相关资源
      最近更新 更多