如何使Haskell代码看起来优雅?

3

我是Haskell的新手,读了一些博客说Haskell代码非常优雅。但是我写的Haskell代码看起来一点也不优雅。 我想要改进的几个方面是:

  • I use case matches on Either values a lot, is using something like fromRight from Data.Either a better option? I also have some code with nested structures, for right values

    case eitherResponse of
        Right response -> return $ toJSON $ response
        Left msg -> Log $ "Error" <> msg
    
  • I have a lot of code which looks like this

    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堆栈类型值。这对我来说很有效,但我想知道这是否是一种好的实践方式? - Tanmay Bhattacharya
你能添加完整的代码吗? - developer_hatch
@Ry-非常好的贡献,如果您不介意,我会将其添加到我的答案中,谢谢! - developer_hatch
这个问题是否更适合在 Stack Exchange 的代码审查部分提出? - user1198582
1
“如果我在IO中有一个顶层函数,那么我编写的每个函数都需要在IO中” - 不是这样,是反过来的,如果某个特定的函数需要IO,那么_调用它的顶层函数_也需要是IO。但是,如果它们不需要IO,那么它调用的所有其他函数都可以是普通的纯函数。 - leftaroundabout
显示剩余3条评论
2个回答

3
你可以通过以下方式改进第二个例子:
pieces <- traverse URI.makePathPiece $ 
   NonEmpty.fromList [functionName, "channel", channel, "chaincode", chaincode]
let path = Just (True, pieces)

我们可以使用 {-# OverloadedStrings #-} 扩展来省略 T.pack。然后使用 traverse 在可遍历的容器 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- 指定导入,以替换 Data.List.NonEmpty.fromList,例如:
import qualified Data.List.NonEmpty as NonEmpty (fromList)

为了简化这条线路:
Just (True, fromList [fname, kch, vch, kca, vca])

你的代码其余部分使用了 do 记号,看起来无法改进(至少根据你展示的代码)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接