Haskell为什么要检查这种类型 导入数据.Monoid 新类型常数a b= 常量{getConstant::a} 推导(Eq、Ord、Show) 实例函子(常数a),其中 fmap(常数a)=常数a 实例(幺半群a)=>Applicative(常数a),其中 纯x=常数(mempty x) _(常数a)=常数a --:t() --()::应用程序f=>f(a->b)->f a->f b --:t常数(和1) --常数(和1)::数值a=>常数(和a)b --常数(和1)常数(和2) --常数{getConstant=Sum{getSum=2}
我的问题是为什么最后一个语句类型要检查 我希望的左侧是f类型(a->b)Haskell为什么要检查这种类型 导入数据.Monoid 新类型常数a b= 常量{getConstant::a} 推导(Eq、Ord、Show) 实例函子(常数a),其中 fmap(常数a)=常数a 实例(幺半群a)=>Applicative(常数a),其中 纯x=常数(mempty x) _(常数a)=常数a --:t() --()::应用程序f=>f(a->b)->f a->f b --:t常数(和1) --常数(和1)::数值a=>常数(和a)b --常数(和1)常数(和2) --常数{getConstant=Sum{getSum=2},haskell,types,Haskell,Types,我的问题是为什么最后一个语句类型要检查 我希望的左侧是f类型(a->b) 其中 f=常数 (a->b)=和1? 我无法应用(Sum 1),因为它已完全应用,但此语句仍能编译。因为这里有两个类型变量: import Data.Monoid newtype Constant a b = Constant { getConstant :: a } deriving (Eq, Ord, Show) instance Functor (Constant a) where fma
其中
f=常数
(a->b)=和1?
我无法应用(Sum 1),因为它已完全应用,但此语句仍能编译。因为这里有两个类型变量:
import Data.Monoid
newtype Constant a b =
Constant { getConstant :: a }
deriving (Eq, Ord, Show)
instance Functor (Constant a) where
fmap _ (Constant a) = Constant a
instance (Monoid a) => Applicative (Constant a) where
pure x = Constant (mempty x )
_ <*> (Constant a) = Constant a
--:t (<*>)
--(<*>) :: Applicative f => f (a -> b) -> f a -> f b
--:t Constant (Sum 1)
--Constant (Sum 1) :: Num a => Constant (Sum a) b
--Constant (Sum 1) <*> Constant (Sum 2)
--Constant { getConstant = Sum { getSum = 2 }}
但您只“存储”第一种类型的值,而第二种类型是一个
但是您的Applicative
实例只关心您拥有的第二个类型变量--b
,即难以捉摸的幻影
这意味着像Constant(Sum 1)
这样的值可以有任何类型的变量作为它们的第二个类型变量——这无关紧要!你可以写:
newtype Constant a b =
Constant { getConstant :: a }
deriving (Eq, Ord, Show)
因为您实际上不需要phantom类型的值
因此,当您写入常量(总和1)常量(总和2)
时,类型检查器会推断出正确的类型:
foo :: Constant Sum (a -> b)
foo = Constant (Sum 1)
bar :: Constant Sum String
bar = Constant (Sum 1)
baz :: Constant Sum (IO [Maybe Int])
baz = Constant (Sum 1)
设foo=常数(和1)::常数和(a->b)
条=常数(总和2)::常数总和a
在富吧
因此,
的左侧确实有类型f(a->b)
,但是f
是常量和
,而不仅仅是常量
左侧是f(a->b)
。这是正确的
记住这里的类型(为了简单起见,让我们制作1::Int
):
我已经为所有添加了显式的。类型检查器可以将a
与任何内容统一起来
试试这个:
Constant (Sum 1) :: forall a. Constant (Sum Int) a
工作正常。对于Const
:
Constant (Sum 1) :: Constant (Sum Int) (a -> b)
所有类型检查,因为最后一个参数可以是任何东西--“Hello”
仅约束第一个参数
但是,您应该注意,您的Applicative
实例不遵守应用规则
Const "Hello" :: Const String Int
Const "Hello" :: Const String Bool
Const "Hello" :: Const String Double
Const "Hello" :: Const String a
Const "Hello" :: Const String (a -> b)
Const "Hello" :: Const String b
u纯y=pure($y)u
特别是违反了:
u <*> pure y = pure ($ y) <*> u
Const“hello”纯4
==常数“你好”常数“”
==常数“”
但是
pure($4)Const“hello”
==常数“常数”你好
==常量“你好”
在您的定义中mempty x
起作用,尽管mempty
的类型是monoida=>a
。尝试将此定义替换为pure x=Constant(mempty x x 127“abc”()x x)
。它有用吗?为什么?;)很好地掌握了应用定律。它似乎是常数,天生就违反了应用定律。@mac10688不完全是;可以为Constant
:)@mac10688编写一个合法的应用程序实例。主要问题是,使用
来“合并”效果应该是将它们合并在一起,也合并它们的效果。按照您编写的方式,您的
会丢失左侧的效果/信息。你怎么能把答案的两面都写进去呢?@JustinL。是的,问题是我正在读哈斯克尔学习书籍的测试版。给出的示例与实际的Const应用程序实例不一致。IRC haskell频道有人演示了。我写了这本书的作者来考虑改变例子。所有优秀的答案,我选择这是因为“F是常数和”把钉子钉在棺材里给我。非常感谢。
Const "Hello" :: Const String Int
Const "Hello" :: Const String Bool
Const "Hello" :: Const String Double
Const "Hello" :: Const String a
Const "Hello" :: Const String (a -> b)
Const "Hello" :: Const String b
u <*> pure y = pure ($ y) <*> u
Const "hello" <*> pure 4
== Const "hello" <*> Const ""
== Const ""
pure ($ 4) <*> Const "hello"
== Const "" <*> Const "hello"
== Const "hello"