- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我如何编写一个通用函数run
,它接受一些 monad 转换器的对象,并调用相应的函数?
给定运行s
,
s
是一个 StateT
,run = runStateT
s
是一个 ReaderT
,run = runReaderT
s
是一个 MaybeT
,run = runMaybeT
我尝试创建一个类型类 Runnable
:
:set -XMultiParamTypeClasses
:set -XFlexibleInstances
class Runnable a b where
run :: a -> b
(//) :: a -> b
(//) = run
instance Runnable (StateT s m a) (s -> m (a, s)) where
run = runStateT
instance Runnable (ReaderT r m a) (r -> m a) where
run = runReaderT
但是当我尝试使用run
时,它不起作用。例如,让我们定义simpleReader
,它在读取时只返回10
:
simpleReader = ReaderT $ \env -> Just 10
runReaderT simpleReader ()
这输出 Just 10
,如预期的那样。
但是,当我尝试使用 run
时,它给了我一个错误:
run simpleReader ()
<interactive>:1:1: error:
• Non type-variable argument in the constraint: Runnable (ReaderT r Maybe a) (() -> t)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall r a t. (Runnable (ReaderT r Maybe a) (() -> t), Num a) => t
如果我像它建议的那样启用 FlexibleContexts
,我会得到一个不同的错误:
<interactive>:1:1: error:
• Could not deduce (Runnable (ReaderT r0 Maybe a0) (() -> t))
(maybe you haven't applied a function to enough arguments?)
from the context: (Runnable (ReaderT r Maybe a) (() -> t), Num a)
bound by the inferred type for ‘it’:
forall r a t. (Runnable (ReaderT r Maybe a) (() -> t), Num a) => t
at <interactive>:1:1-19
The type variables ‘r0’, ‘a0’ are ambiguous
• In the ambiguity check for the inferred type for ‘it’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the inferred type
it :: forall r a t. (Runnable (ReaderT r Maybe a) (() -> t), Num a) => t
最佳答案
简短回答:您需要对您的类有功能依赖。
长答案:
当编译器看到 run
时,它需要找到 Runnable
的适当实例,以便确定要使用 run
的哪个实现。为了找到那个实例,它需要知道 a
和 b
是什么。它知道 a
是一个 ReaderT
,所以一个被覆盖了。但是 b
是什么?
编译器看到您正在使用 b
作为函数,将 ()
作为参数传递给它。因此,编译器认为 b
的形状必须是 () -> t
,其中 t
尚不清楚。
这就是它有点停止的地方:编译器没有地方可以从中获取 t
,因此它不知道 b
,因此它找不到合适的实例,如此轰隆!
但是对于这种情况是有补救办法的。如果我们仔细观察您的 Runnable
类的实际含义,很容易看出 b
应该由 a
严格定义。也就是说,如果我们知道 monad 是什么,我们就知道返回值是什么。因此,编译器应该可以通过知道a
来确定b
。但遗憾的是,编译器并不知道这一点!
但是有一种方法可以向编译器解释这一点。叫做“函数依赖”,是这样写的:
class Runnable a b | a -> b where
此符号 a -> b
告诉编译器 b
应该由 a
明确确定。这将意味着,一方面,编译器不会让您定义违反此规则的实例,另一方面,它将能够通过了解找到合适的 Runnable
实例a
,然后根据该实例确定 b
。
关于haskell - 如何编写调用 `run` 或 `runStateT` 的函数 `runReaderT`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58613931/
我如何编写一个通用函数run,它接受一些 monad 转换器的对象,并调用相应的函数? 给定运行s, 如果 s 是一个 StateT,run = runStateT 如果 s 是一个 ReaderT,
我是一名优秀的程序员,十分优秀!