在Haskell中记录具有多个构造函数的类型 [英] Record types with multiple constructors in haskell

查看:52
本文介绍了在Haskell中记录具有多个构造函数的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,当我使用Haskell编写某些东西时,我需要具有多个构造函数的记录. 例如.我想开发某种逻辑方案建模.我想到了这样的类型:

Very often when I write something using Haskell I need records with multiple constructors. E.g. I want to develop some kind of logic schemes modelling. I came up to such type:

data Block a = Binary {
      binOp  :: a -> a -> a
    , opName :: String
    , in1 :: String
    , in2 :: String
    , out :: String
} | Unary {
      unOp  :: a -> a
    , opName :: String
    , in_ :: String
    , out :: String
}

它描述了两种类型的块:二进制(如和,或等)和一元(如非).它们包含核心功能,输入和输出信号.

It describes two types of blocks: binary (like and, or etc.) and unary (like not). They contain core function, input and output signals.

另一个示例:键入以描述控制台命令.

Another example: type to describe console commands.

data Command = Command { info :: CommandInfo
                       , action :: Args -> Action () }
             | FileCommand { info :: CommandInfo
                           , fileAction :: F.File -> Args -> Action ()
                           , permissions :: F.Permissions}

FileCommand需要附加字段-必需的权限及其操作接受文件作为第一个参数.

FileCommand needs additional field - required permissions and its action accept file as a first parameter.

当我阅读和搜索有关Haskell的主题,书籍等时,似乎不常见的是同时使用具有记录语法的类型和许多构造函数.

As I read and search topics, books etc. about Haskell, it seems that it is not common to use types with record syntax and many constructors simultaneously.

那么问题是:这个模式"不是散乱的,为什么?如果是这样,如何避免呢?

So the question: is this "pattern" is not haskell-way and why? And if it is so, how to avoid it?

P.S.建议的布局中哪一种更好,或者可读性更高?因为我找不到其他来源的任何示例和建议.

P.S. Which from proposed layouts is better, or maybe there is more readable one? Because I can't find any examples and suggestions in other sources.

推荐答案

当事情开始变得复杂时,请分而治之.通过从较简单的实体组成,而不是通过将所有功能都放到一个地方来创建复杂实体.事实证明,这不仅是在Haskell中,而且是一般编程的最佳方法.

When things start getting complicated, divide and conquer. Create complex entities by composing from simpler ones, not by ramming all the functionality into a single place. This has proven to be the optimal approach to programming in general, not just in Haskell.

您的两个示例都可以受益于分离.例如

Both your examples can benefit from separation. E.g.

data Block a = BinaryBlock (Binary a) | UnaryBlock (Unary a)

data Binary a = Binary {
  ...
}
data Unary = Unary {
  ...
}

现在,您将BinaryUnary分开了,并且能够为每个函数单独编写专用功能.这些功能将更容易理解和维护.

Now you have Binary and Unary separated and you're able to write dedicated functions for each of them in isolation. Those functions will be much simpler and easier to reason about and maintain.

将这些类型放在单独的模块中也将使您受益,这将解决字段名冲突. Block的最终API将涉及非常简单的模式匹配,并转发到BinaryUnary的专用功能.

You'll also be able to benefit from putting those types in separate modules, which will resolve the field names collision. The final API for Block will be about very simple pattern matches and forwarding to specialised functions of Binary and Unary.

这种方法是可扩展的.无论您的实体有多复杂或遇到什么问题,您都可以随时添加新的分解级别.

This approach is scalable. No matter how complex your entities or problems are you're always free to add another level of decomposition.

这篇关于在Haskell中记录具有多个构造函数的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆