是否存在使用代数数据类型或多态性的 OOP 抽象类的 Haskell 等效项?

2023-12-31

在Haskell中,是否可以编写一个带有签名的函数,该函数可以接受两种不同(尽管相似)的数据类型,并根据传入的类型进行不同的操作?

一个例子可能会让我的问题更清楚。如果我有一个名为myFunction,以及两种名为MyTypeA and MyTypeB,我可以定义myFunction这样它只能接受类型的数据MyTypeA or MyTypeB作为它的第一个参数?

type MyTypeA = (Int, Int, Char, Char)
type MyTypeB = ([Int], [Char])

myFunction :: MyTypeA_or_MyTypeB -> Char
myFunction constrainedToTypeA = something
myFunction constrainedToTypeB = somethingElse

在 OOP 语言中,您可以像这样编写我想要实现的目标:

public abstract class ConstrainedType {
}

public class MyTypeA extends ConstrainedType {
    ...various members...
}

public class MyTypeB extends ConstrainedType {
    ...various members...
}

...

public Char myFunction(ConstrainedType a) {
    if (a TypeOf MyTypeA) {
        return doStuffA();
    }
    else if (a TypeOf MyTypeB) {
        return doStuffB();
    }
}

我一直在阅读有关代数数据类型的内容,我认为我需要定义一个 Haskelltype,但我不确定如何定义它以便它可以存储一种或另一种类型,以及如何在我自己的函数中使用它。


是的,你是对的,你正在寻找代数数据类型。有一个关于它们的很棒的教程:向你学习 Haskell http://learnyouahaskell.com/making-our-own-types-and-typeclasses#algebraic-data-types.

根据记录,OOP 中的抽象类概念实际上在 Haskell 中有三种不同的翻译,ADT 只是其中之一。以下是这些技术的快速概述。

代数数据类型

代数数据类型对抽象类的模式进行编码,该抽象类的子类是已知的,并且其中函数通过向下转换来检查该对象是哪个特定实例的成员。

abstract class IntBox { }

class Empty : IntBox { }

class Full : IntBox {
    int inside;
    Full(int inside) { this.inside = inside; }
}

int Get(IntBox a) {
    if (a is Empty) { return 0; }
    if (a is Full)  { return ((Full)a).inside; }
    error("IntBox not of expected type");
}

翻译成:

data IntBox = Empty | Full Int

get :: IntBox -> Int
get Empty = 0
get (Full x) = x

功能记录

这种风格不允许向下投射,所以Get上面的函数无法用这种风格来表达。所以这是完全不同的东西。

abstract class Animal { 
    abstract string CatchPhrase();
    virtual void Speak() { print(CatchPhrase()); }
}

class Cat : Animal {
    override string CatchPhrase() { return "Meow"; }
}

class Dog : Animal {
    override string CatchPhrase() { return "Woof"; }
    override void Speak() { print("Rowwrlrw"); }
}

它在 Haskell 中的翻译不会将类型映射到类型。Animal是唯一的类型,并且Dog and Cat被压缩到它们的构造函数中:

data Animal = Animal {
    catchPhrase :: String,
    speak       :: IO ()
}

protoAnimal :: Animal
protoAnimal = Animal {
    speak = putStrLn (catchPhrase protoAnimal)
}

cat :: Animal
cat = protoAnimal { catchPhrase = "Meow" }

dog :: Animal
dog = protoAnimal { catchPhrase = "Woof", speak = putStrLn "Rowwrlrw" }

这个基本概念有几种不同的排列。不变的是抽象类型是记录类型,其中方法是记录的字段。

编辑:评论中对此方法的一些微妙之处进行了很好的讨论,包括上述代码中的错误。

类型类

这是我最不喜欢的 OO 思想编码。它对于 OO 程序员来说很舒服,因为它使用熟悉的单词并将类型映射到类型。但是当事情变得复杂时,上面的函数记录方法往往更容易使用。

我将再次对 Animal 示例进行编码:

class Animal a where
    catchPhrase :: a -> String
    speak       :: a -> IO ()

    speak a = putStrLn (catchPhrase a)

data Cat = Cat 
instance Animal Cat where
    catchPhrase Cat = "Meow"

data Dog = Dog
instance Animal Dog where
    catchPhrase Dog = "Woof"
    speak Dog = putStrLn "Rowwrlrw"

这看起来不错,不是吗?当您意识到尽管它看起来像面向对象,但它实际上并不像面向对象那样工作时,困难就来了。您可能想要一份动物列表,但您现在能做的最好的事情是Animal a => [a],同质动物的列表,例如。仅包含猫或仅包含狗的列表。然后你需要制作这个包装类型:

{-# LANGUAGE ExistentialQuantification #-}

data AnyAnimal = forall a. Animal a => AnyAnimal a
instance Animal AnyAnimal where
    catchPhrase (AnyAnimal a) = catchPhrase a
    speak (AnyAnimal a) = speak a

进而[AnyAnimal]是您想要的动物列表。然而事实证明AnyAnimal暴露exactly与自身相同的信息Animal在第二个例子中记录,我们只是以一种迂回的方式进行了处理。因此,为什么我不认为类型类是一种非常好的 OO 编码。

本周的版本就这样结束了信息太多了!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否存在使用代数数据类型或多态性的 OOP 抽象类的 Haskell 等效项? 的相关文章

  • Spring RESTful控制器方法改进建议

    我是 Spring REST 和 Hibernate 的新手 也就是说 我尝试组合一个企业级控制器方法 我计划将其用作未来开发的模式 您认为可以通过哪些方法来改进 我确信有很多 RequestMapping value user metho
  • IE9-11 检测变换样式:preserve-3d

    我为一个项目制作了一个 3d 类型的菜单 自然 IE 会引起问题 因为 IE10 即使 3d 变换工作 也不支持变换样式 preserve 3d 我尝试了解决方法 通过对 3d 菜单容器的每个子元素应用变换 但至少可以说 动画看起来很糟糕
  • 文本溢出:省略号显示不同的字符

    我这里遇到了一些 CSS 问题 看这张图片 https www flickr com photos 125543025 N07 saved 1 在此图像中 我为文本 INTENSE TRAINING 添加了 CSS 样式 sample st
  • 我们什么时候应该在 Django 中使用“db_index=True”?

    当我们应该定义db index True在模型字段上 我正在尝试优化应用程序并且我想了解更多信息db index 什么情况下我们应该使用它 文档说使用db index True在模型字段上用于加速查找 但在存储和内存方面略有缺点 我们应该使
  • 如何制作过期/签名视频嵌入网址

    我是新来的 正在学习网络开发等等 我只知道如何将我的视频嵌入网站中 任何菜鸟都可以轻松获得源代码 他们也可以嵌入它 但在许多网站中 视频 src 均使用重定向器链接进行编码 例如 它会在一段时间后过期 在本例中是一天 我了解到这是一个签名网
  • Qt 布局,在小部件大小更改后调整到最小大小

    基本上我有一个QGridLayout里面有一些小部件 最重要的是 2 个标签 我用它们将图像绘制到屏幕上 好吧 如果用户愿意 他可以更改传入图像的分辨率 从而强制标签调整大小 我们假设标签的初始大小是320x240 用户将 VideoMod
  • bash:gitolite:找不到命令

    我正在尝试使用 Gitolite 在 Gitlab 中创建一个新分支 我完成安装步骤 当我遇到 设置 gitolite 部分时 我遇到了麻烦 我跟着这个link http sitaramc github com gitolite setup
  • 如何在 kubernetes 中将秘密标记为可选?

    来自文档 除非将秘密标记为可选 否则必须先创建秘密 然后再将其作为环境变量在 pod 中使用 引用不存在的 Secret 将阻止 pod 启动 如何将秘密标记为可选 您正在寻找的是 name ENV NAME valueFrom secre
  • ASP.NET Core MVC 视图组件搜索路径

    在此处的文档中 https learn microsoft com en us aspnet core mvc views view components view aspnetcore 2 2 https learn microsoft
  • xsi:type 属性搞乱了 C# XML 反序列化

    我使用 XSD exe 根据 XML 架构 xsd 文件 自动生成 C 对象 我正在反序列化 OpenCover 输出 但其中一个部分类未正确生成 这是导致异常的行
  • 一些基本的 PHP 问题 [已关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我只是有一些基本的 php 问题来加深我对学习的理解 但我找不到简单的答案 我有一个 php ajax 应用程序 它生成 mysql
  • If else 在 Web 网格列中

    如何在 webgrid 列中添加条件 if else grid GetHtml tableStyle table table bordered columns grid Columns grid Column RealName Name g
  • View.post(),以及当Runnables被执行时

    我最初的问题是需要知道我的根的高度和宽度View这样我就可以进行程序化的布局更改 就我的目的而言 我不一定需要在onCreate 对于我来说 以编程方式添加我的孩子就足够了View根布局完成后 因此我很乐意使用onWindowFocusCh
  • SimpleIoC - 在缓存中找不到类型:Windows.UI.Xaml.Controls.Frame

    第一次由 SimpleIoC 实例化我的 ViewModel 时 我遇到了以下错误 我相信我已经按应有的方式设置了容器 但由于某种原因 我仍然收到以下错误 任何想法或帮助将非常感激 Microsoft Practices ServiceLo
  • 将 Angular Web 组件 EventEmitter 监听到 javascript

    我在以下工具的帮助下创建了一个小型网络组件本文 https medium com IMM9O web components with angular d0205c9db08f使用角度元素 其中包括 Input and Output 我能够将
  • java'assert'和'if(){}else exit;'之间的区别

    java和java有什么区别assert and if else exit 我可以用吗if else exit代替assert 也许有点谷歌 您应该记住的主要事情是 if else 语句应该用于程序流程控制 而assert 关键字应该仅用于
  • R闪亮:使用闪亮的JS从数据表中获取信息

    我想读出所有列名称以及它们在数据表中显示的顺序 由于不同的原因 我无法使用 stateSave 等选项 我对 JS 没有什么把握 但我确信用它可以完成 所以我需要你帮助我 我尝试过类似的代码片段 datatable data callbac
  • 从 JavaScript 中的 OnClientClick 事件中阻止 C# 中的 asp:Button OnClick 事件?

    我有一个asp Button在我的网页上 它调用 JavaScript 函数和代码隐藏方法 后者进行调用以导航到另一个页面 在 JavaScript 函数中 我正在检查条件 如果不满足这个条件 我想中止导航 以便OnClick方法未被调用
  • 自定义字符串查询操作的 Linq to NHibernate 可扩展性?

    我希望能够在 NHibernate Linq 表达式中使用自定义字符串查询 举例来说 这只是一个例子 我希望能够选择包含属性的实体 该属性是特定字符串的字谜 var myEntities EntityRepository AllEntiti
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐

  • 重命名后项目崩溃

    如果我在 XCode 中的导航器视图中更改 iOS 项目的名称 Xcode 4 中的 Project gt Rename 相当于什么 https stackoverflow com questions 6077876 what is the
  • 如何使用 jQuery animate() 方法使 div 左右移动?

    请看一下这个 http jsfiddle net tmPfV http jsfiddle net tmPfV 如果您单击右侧 则该框将向右移动 如果您单击左侧 则该框将向左移动 但是 如果您再次单击右键 则什么也没有 我怎样才能让它左右移动
  • 尝试解码数据(将 Abs 导出到 MySQL)

    我有数据库表 DROP TABLE translation en lt CREATE TABLE translation en lt id INTEGER lt translation WIDEMEMO BLOBBlockSize 1024
  • 如何使用 Log4j 和 Storm Framework 将日志写入文件?

    我在 Storm 中使用 log4j 记录到文件时遇到了一些问题 在提交我的拓扑之前 即在我的主要方法中 我编写了一些日志语句并使用以下方法配置了记录器 PropertyConfigurator configure myLog4jPrope
  • 组装键盘IO口

    我看过以下内容topic https stackoverflow com questions 219120 x86 assembly protected mode keyboard access 我有兴趣通过 IN OUT 指令联系键盘并设
  • Spring Web Flow - 如何使用对话范围中已有的值设置单元测试?

    我正在开发一个使用 Spring Web Flow 2 0 的项目 我正在尝试对从决策状态开始的流程进行单元测试 决策状态检查位于conversationScope 我不知道如何将值插入到conversationScope用于单元测试 我努
  • 根据系统动态判断整数类型(c++)

    我正在编写一个程序 以每 32 位 即一次 4 个字节 为单位将数据存储到文件中 我在64位Windows系统中编写代码 但我使用的编译器是32位 mingw32 在当前系统中 int和long的大小是相同的 都是32位 4字节 我目前正在
  • 使用 AWK 将多个文件中的列添加到 csv 表

    我希望通过使用 AWK 从多个文件中获取值来构建 csv 表 我让它处理两个文件 但我无法扩展它 我目前正在获取第二个文件的输出 并附加第三个文件 依此类推 以下是示例文件 file1 file2 file3 file4 100 45 1
  • 无法安装包收缩[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我跑了 pip install contractions in jupyter notebook并且无法安装库收缩并显示
  • 模式同义词签名:必需与提供的约束

    我想我明白了 不寻常形式 的约束 https downloads haskell org 7Eghc 8 10 5 docs html users guide glasgow exts html typing of pattern syno
  • Reactjs - 输入默认值已设置但未显示

    注意到一些奇怪的现象 即为输入设置了 defaultValue 但有时刷新页面时它不可见 我尝试过 console log 然后组件在加载数据时重新渲染多次 在最后一次重新渲染时 组件包含所需的值 如屏幕截图所示 但未显示 知道为什么吗 谢
  • 关闭 GDB 中设置断点的确认[重复]

    这个问题在这里已经有答案了 在共享库上设置断点 gdb b file c 278 No symbol table is loaded Use the file command Make breakpoint pending on futur
  • 文本编辑器告诉光标位置的索引

    我需要一个文本编辑器来告诉我光标的位置 这样我就可以确定要加载到字符串中的文本范围 不幸的是 我尝试过的文本编辑器 TextWrangler Aquamacs EditPad 只告诉我光标所在的行号以及该行上的字符索引 我需要从文件开头到该
  • 如何聚合来自异步生产者的数据并将其写入文件?

    我正在学习 C 中的异步 等待模式 目前我正在尝试解决这样的问题 有一个生产者 硬件设备 每秒生成 1000 个数据包 我需要将这些数据记录到文件中 该设备只有一个ReadAsync 一次报告单个数据包的方法 我需要缓冲数据包并按照它们生成
  • 将用户身份验证详细信息存储在单独的表中的优点

    我在 mysql 中有一个用户表 其中包含所有用户数据 名字 姓氏 地址等 但是我是否应该将身份验证详细信息存储在另一个表 用户名 密码 中并通过用户 ID 链接这两个表 这其中有什么道理吗 是不是更安全 或者它只是添加额外的编码 这其中有
  • 将 Typescript 2.3 模块发布到 NPM 以供 Angular 4 使用

    里面有相关说明在 Typescript 中编写 NPM 模块 https stackoverflow com questions 30928253 writing npm modules in typescript 但是它已经过时了 现在有
  • 在 Swift 中创建像这样的普通框窗口吗?

    下面是 App Store 上 Squish 应用程序的屏幕截图 我怎样才能制作一个这样的窗口 带有圆角并且标题栏和内容之间没有分隔符 唯一的区别是我想在标题栏上有一个标题 简而言之 如何制作一个如图所示但带有标题的窗口 在Xcode中创建
  • 在 BS 3 中对齐标签和文本框

    我正在尝试使用 Bootstrap 3 对齐标签和文本框 这不起作用 因为 开始日期 被包装了 我也尝试过 form horizo ntal 但对我没有帮助 div class row div class col xs 3 input gr
  • 为什么我的 Swift 包获取了错误的主体类?

    我做了一个捆绑目标 它的Info plist文件指定一个非常具体的类 我们称之为PrincipalClass 应该是它的主要类 这个类是用 Swift 编写的 并且具有 objc属性 这Info plist文件已正确复制到捆绑包中 并且我已
  • 是否存在使用代数数据类型或多态性的 OOP 抽象类的 Haskell 等效项?

    在Haskell中 是否可以编写一个带有签名的函数 该函数可以接受两种不同 尽管相似 的数据类型 并根据传入的类型进行不同的操作 一个例子可能会让我的问题更清楚 如果我有一个名为myFunction 以及两种名为MyTypeA and My