【问题标题】:How to make code look elegant in Haskell?如何让 Haskell 中的代码看起来很优雅?
【发布时间】:2019-11-29 08:23:30
【问题描述】:

我是 Haskell 的新手,我已经阅读了有关 Haskell 代码如何非常优雅的博客。我编写 Haskell 代码的方式看起来一点也不优雅。 我想改进的一些领域是

  • 我经常在 Either 值上使用大小写匹配,正在使用类似的东西 fromRight 从 Data.Either 更好的选择?我也有一些嵌套结构的代码,用于正确的值

    case eitherResponse of
        Right response -> return $ toJSON $ response
        Left msg -> Log $ "Error" <> msg
    
  • 我有很多这样的代码

    fname <- URI.mkPathPiece functionname
    kch <- URI.mkPathPiece $ T.pack "channel"
    vch <- URI.mkPathPiece channel
    kca <- URI.mkPathPiece $ T.pack "chaincode"
    vca <- URI.mkPathPiece chaincode
    let path = Just (True, Data.List.NonEmpty.fromList [fname, kch, vch, kca, vca])
    

我真的不喜欢它的外观,我该如何改进?

另外,对我来说,Haskell 与“do”块中的命令式编程非常相似。这是 Haskell 代码的外观还是我在这里走错了路?

【问题讨论】:

  • 问题是,如果我在 IO 中有一个顶级函数,我在它下编写的每个函数都需要在 IO 中,所以当我完成时,我编写的每个函数都结束了向上返回 IO/一些 Monad Trasformer 堆栈类型值。它对我有用,我只是想了解这是否是一个好习惯?
  • 可以添加完整的代码吗?
  • 不是很重要的事情,但{-# LANGUAGE OverloadedStrings #-} 我认为你可以跳过T.pack 而直接使用URI.mkPathPiece "channel"
  • 还有类似foo &lt;- mapM URI.mkPathPiece $ NonEmpty.fromList [functionname, "channel", channel, "chaincode", chaincode](使用import qualified
  • “如果我在 IO 中有一个顶级函数,那么我在其下编写的每个函数都需要在 IO 中”——没有,是什么让你这么认为?相反,如果某个特定函数需要IO调用它的顶级函数 也需要IO。但是它调用的所有其他函数都可以是普通的纯函数,如果它们不需要IO

标签: haskell


【解决方案1】:

你可以像这样改进你的第二个例子:

pieces <- traverse URI.makePathPiece $ 
   NonEmpty.fromList [functionName, "channel", channel, "chaincode", chaincode]
let path = Just (True, pieces)

我们使用{-# OverloadedStrings #-} 扩展名省略了T.packs。然后使用traverse 将一元函数映射到NonEmpty 上,NonEmpty 是一个可遍历的容器。

我需要更多上下文来给出第一个示例的具体替代方案,但如果您有嵌套结构,例如:

case eitherResponse of
    Left -> some error ...
    Right x -> 
        case someFunction x of
            Left -> some error ...
            Right y -> ...

这种链接正是Either/ExceptTMonad 实例所做的。你可以让它看起来像这样:

do x <- eitherResponse
   y <- someFunction x

是时候了解单子转换器了!

【讨论】:

    【解决方案2】:

    我只是想用一个辅助函数的子函数来改进这部分:

    toJsonOrError (Right response) = return $ toJSON $ response
    toJsonOrError (Left msg) = Log $ "Error" <> msg
    

    您也可以导入限定为@Ri-pointed,以替换Data.List.NonEmpty.fromList,如:

    import qualified Data.List.NonEmpty as NonEmpty (fromList)
    

    简化线路:

    Just (True, fromList [fname, kch, vch, kca, vca])
    

    您的代码的其余部分是 do 表示法,看起来无法改进(至少与您显示的代码一样)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      • 2011-05-03
      • 2019-01-27
      • 2013-11-17
      相关资源
      最近更新 更多