Haskell-适用于任一方

如何解决Haskell-适用于任一方

我正在尝试理解Applicative和任一左派。来源:

80

我无法理解instance Applicative (Either e) where pure = Right Left e <*> _ = Left e Right f <*> r = fmap f r 部分。这是没有道理的,因为:

Left e <*> _ = Left e

将返回Left (+3) <*> Right 5 ,同时:

Left (+3)

将返回Right (+1) <*> Left 3 。问题是不一致。为什么要这样做?如果我的问题不够清楚,我深表歉意。谢谢!

解决方法

TL; DR,这是一个故意的设计决定。

您应该将Right视为“默认”状态,并将Left视为“后备”状态。我确实想对您的上述声明做一些小的更正。 Left (+3) <*> Right 5不会像您所说的那样产生(+3),而是产生Left (+3)。这是一个重要的区别。第二个更正是Right (+1) <*> Left 3不是Left 4,而是Left 3。同样,这对于了解正在发生的事情很重要。

<*>运算符不能在Either上对称的原因是,LeftRight构造函数的类型不同。让我们看看专门针对<*>仿函数的Either的类型:

(<*>) :: Either a (b -> c) -> Either a b -> Either a c

请注意,只有第一个参数的Right面才需要是一个函数。这样,您就可以使用(<*>)将这样的参数链接在一起:

Right (+) <$> Right 3 <*> Right 2
> Right 5

但是如果第一个参数是Left 3

Right (+) <$> Left 3 <*> Right 2
> (Right (+) <$> Left 3) <*> Right 2
> Left 3 <*> Right 2
> Left 3

这也意味着,当(<*>)Left的类型不同时,通常可以使用Right。如果Left (+3) <*> Right 5应该产生Left 8,那么Left (++ "world") <*> Right 5应该产生什么,假设它们都可以被强制转换为同一类型,即Num a => Either (String -> String) a?当LeftRight不是同一类型时,不可能给出令人满意的答案,因为它们Either被限制为只能携带一种类型严重阻碍了实用程序。

这还允许您以某种方式将Left值视为例外。如果在任何阶段最终得到一个Left值,Haskell将停止执行计算,而只是将Left值一直向上级联。这也恰好与许多人对编程的思考方式相匹配。您可以想象为LeftRight值创建替代的计算集,但是在许多情况下,最终还是要用Left来填充id计算,因此这在实践中并没有太大的限制。如果要执行一对分支计算中的一个,则应使用常规分支语法(例如警卫队,模式或caseif语句),然后将值包装在{{1}中}。

,

考虑实例的以下等效定义:

instance Applicative (Either e) where
    pure = Right
    lhs <*> rhs = case lhs of
                      Right f -> fmap f rhs
                      otherwise -> lhs

如果lhs不是Right,则它必须是Left,因此我们将其原样返回。实际上,我们根本不需要与包装的值匹配。如果Right,我们将遵循Functor实例来查找返回的内容。

instance Functor (Either a) where
    fmap f (Right x) = Right (f x)
    fmap _ l = l

我再次给出一个定义,强调Left值的 content 无关紧要。如果第二个参数不是Right,则不必在其上显式匹配。它必须是Left,我们可以原样返回它。

,

如果您想知道Right … <*> Left …仍如何返回Left,那是因为在此定义中调用了fmap

instance Applicative (Either e) where
    pure          = Right
    Left  e <*> _ = Left e
    Right f <*> r = fmap f r

如果我们为fmap扩展Either的定义,那么<*>的定义如下:

Left  e <*> _ = Left e
Right f <*> r = case r of
  Left e -> Left e
  Right x -> Right (f x)

或者,更对称地写明所有情况:

Left  e1 <*> Left  _e2 = Left e1      -- 1
Left  e  <*> Right _x  = Left e       -- 2
Right _f <*> Left  e   = Left e       -- 3
Right f  <*> Right x   = Right (f x)  -- 4

我用下划线_标记了所丢弃的值。

请注意,当两个输入均为Right时,返回Right only 情况。实际上,这是可能唯一返回Right的时间。

在情况(4)中,我们只有一个Right (f :: a -> b)和一个Right (x :: a);我们没有e,因此我们无法返回Left,而获得b的唯一方法是将f应用于{{ 1}}。

在情况(1),(2)和(3)中,我们必须返回一个x,因为至少有一个输入是Left,所以我们缺少了{{1 }}或我们需要产生Left的{​​{1}}。

在情况(1)中,当两个输入均为a -> b时,a偏向第一个参数。

有一种类似于b的类型称为Left,它组合其“失败”情况,而不是选择其中一种,但受其限制:仅Either,而Either既是Validation又是Applicative

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

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 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 -&gt; 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(&quot;/hires&quot;) 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&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res