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为什么要检查这种类型 导入数据.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)
其中
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"