Haskell函子实现处理“ BOX”?

如何解决Haskell函子实现处理“ BOX”?

在范畴论中,Functor的概念如下:

https://ncatlab.org/nlab/show/functor

enter image description here

在Haskell中,Functor类型可以表示为:

fmap :: (a -> b) -> f a -> f b

https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Functor.html

我可以看到两者之间确实很对应。

但是,一旦我们实际尝试将Functor概念简化为代码,似乎就不可能像上图所示那样简单地定义Ffmap

实际上,有一篇关于Functor / Monad的著名文章。

Functors,Applicatives,And Monads In Pictures

在这里

足够简单。让我们通过说任何值都可以在上下文中来扩展这一点。现在,您可以将上下文视为可以在其中添加值的框:

enter image description here

这是我们编写fmap(+3)(仅2月)时幕后发生的事情:

enter image description here

我对Functor的总体看法是类别理论中的 Functor概念,而与“包装箱”进行包装的概念与之相匹配。

问题点1。

fmap :: (a -> b) -> f a -> f b

https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Functor.html

在Haskell中“ BOX”与“包装”之间的实际实现在哪里?

问题点2。

为什么分类理论中的 Functor概念与“包装箱”进行包装的概念不匹配?

编辑:

即使对于IO函子,在编写过程中,f也已展开:

  // f is unwrapped in composition process
  const compose = g => f => x => g(f(x));

  const fmap = compose;

  const print = a => () => console.log(a);
  
  // safely no side-effect
  const todo = fmap(print("bar"))(print("foo"));

  //side effect
  todo(undefined); // foo bar

  // with pipleline operator (ES.next)
  //
  //  const todo = print("foo")
  //    |> fmap(print("bar"))
  //    |> fmap(print("baz"));

  //  todo(undefined); // foo bar baz
  

解决方法

类别理论的思想是如此抽象,以至于任何试图提供直观介绍的人都有将概念简化到可能使人感到困惑的风险。作为an article series in this space的作者,我可以证明,在有人误解文本之前,并不需要太多不精确的语言。

我不知道那篇文章,但我相信它可能表现出相同的特征。包装/解开隐喻适合大部分函子(例如^(Q:.*?\n) # Matches "Q:" at the beginning of the line,followed by # some optional text ending with a line-feed. (?!Q:) # Not immediately followed by another "Q:". ( # Start of the second capturing group. [\s\S]+? # Matches one or more characters (including line breaks) - non-greedy. (?=^Q:|\Z) # Stop matching if either followed by "Q:" or is at the end of the string. ) # End of the second capturing group. Maybe[]等),但并非全部。

众所周知,您是not supposed to unwrap IO;那是设计使然。在这一点上,包装/展开的隐喻崩溃了。面对Either l,它不再有效。

确实,这些概念不匹配。我想说,wrap / unwrap隐喻可能是有用的介绍,但一如既往,可以扩展隐喻的数量是有限制的。

如何实现IO实例? Haskell的大多数介绍将向您展示如何为Functorfmap和其他几种类型编写Maybe。如果有机会的话,自己实施也是一种很好的练习。

GHC及其生态系统是开源的,因此,如果您想知道如何实现特定实例,可以随时查看源代码。

同样,[]是该规则的一个大例外。据我了解,其IOFunctorApplicative等实例不是在(Safe)Haskell中实现的,而是在一小部分不安全代码(C或C ++,我相信)构成了编译器和/或运行时环境的核心。 Monad没有进行任何(明确,可见,安全的)解包操作。我认为将IO的{​​{1}}实例看成是保留结构的映射会更有用。

有关类别理论与Haskell之间对应关系的更多详细信息,我建议使用Bartosz Milewski's article series on the topic

,

查看图片中的箭头。从功能器级别回到非功能器级别是没有办法。您将需要一个从F(x)x的函数,但是-如您所见-没有定义。

有一些特定的函子(例如Maybe)具有“展开”功能,但此功能始终是附加功能,它是函子的顶部。例如,您可能会说:Maybe是一个函子,它还具有一个有趣的属性:有一个部分函数将Maybe X映射到X,并反转pure

更新(在出现其他问题之后)盒子和函子的概念根本不匹配。而且,据我所知,没有找到对函子(或monad或应用程序)的很好的隐喻-并不是因为缺乏尝试。这甚至不足为奇:大多数抽象都缺乏良好的隐喻,正是因为抽象和隐喻是相反的(从某种意义上来说)。

抽象将概念剥离到其核心,仅保留最重要的要素。另一方面,隐喻扩展了概念,扩大了语义空间,暗示了更多的含义。当我说:“您的眼睛有巧克力的颜色”时,我是在抽象“颜色”的概念。但是,我还隐喻地将眼睛和巧克力联系起来:我建议它们比颜色具有更多的共同点:柔滑的质地,甜美,愉悦-所有这些概念都存在,尽管都没有命名。如果我说“您的眼睛有排泄物的颜色”,则使用的抽象将完全相同-但隐喻的含义是:非常不同。即使逻辑学家从技术上理解这句话并不令人反感,我也不会对逻辑学家说出来。

在进行自动驾驶时,大多数人会以隐喻而不是抽象的方式思考。在用前者解释后者时必须小心,因为含义会溢出。当您听到“盒子”的声音时,脑海中的自动驾驶仪会告诉您可以放入和取出物品。函子不是那样的。因此,这个比喻具有误导性。

Functor体现了...盒子或包装纸的抽象,但使我们无需拆开即可处理它们的内容。缺少解包正是使函子变得有趣的原因:否则fmap仅仅是解包,应用函数并将结果包装起来的语法糖。研究函子使我们了解不解包价值的可能性—更好的方法和更具启发性的功能,使我们了解不解包的不可能。导致应用程序,箭头和monad的步骤向我们展示了如何通过允许执行其他操作来克服某些限制,但stukk 绝不允许展开,因为如果我们允许展开,则这些步骤将毫无意义(即变得微不足道)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-