[英]Haskell why does this type check
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 }}
My question is why does the last statement type check? 我的问题是为什么最后一个语句类型检查?
I expected the left side of <*> to be of type f ( a -> b) 我希望<*>的左边是f(a - > b)类型
Where 哪里
f = Constant f =常数
(a -> b) = Sum 1? (a - > b)=总和1?
There's nothing I can apply to (Sum 1) because it is fully applied, yet this statement compiles. 我无法应用于(Sum 1),因为它已完全应用,但此语句编译。
The left side is f (a -> b)
. 左边是
f (a -> b)
。 This is correct. 这是对的。
Remember the type here (let's make 1 :: Int
for simplicity): 记住这里的类型(为简单起见,让我们创建
1 :: Int
):
Constant (Sum 1) :: forall a. Constant (Sum Int) a
I've added the explicit forall
. 我添加了明确的
forall
。 The type checker can unify a
with anything. 类型检查能够统一
a
任何事情。
Try this one: 试试这个:
Constant (Sum 1) :: Constant (Sum Int) (a -> b)
Works fine. 工作正常。
For Const
: 对于
Const
:
(<*>) :: Const c (a -> b) -> Const c a -> Const c b
Your input was a Const c (a -> b)
a Const ca
. 你的输入是一个
Const c (a -> b)
一个Const ca
You gave a Const cb
in return -- if x :: c
, then Const x :: Const ca
, for any a
. 你给了一个
Const cb
作为回报 - 如果x :: c
,那么Const x :: Const ca
,对于任何a
。 It can be Const c Int
, Const c Bool
, etc. 它可以是
Const c Int
, Const c Bool
等。
For example: 例如:
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
all typecheck, because the last parameter can be anything -- "Hello"
only constrains the first parameter. 所有类型检查,因为最后一个参数可以是任何东西 -
"Hello"
只约束第一个参数。
However, you should note that your Applicative
instance doesn't obey the Applicative laws. 但是,您应注意,您的
Applicative
实例不遵守适用法律。
u <*> pure y = pure ($ y) <*> u
in particular is violated: 特别是违反了:
Const "hello" <*> pure 4
== Const "hello" <*> Const ""
== Const ""
but 但
pure ($ 4) <*> Const "hello"
== Const "" <*> Const "hello"
== Const "hello"
Because you have two type variables here: 因为这里有两个类型变量:
newtype Constant a b =
Constant { getConstant :: a }
deriving (Eq, Ord, Show)
But you only "store" values of the first type, and the second is a phantom . 但是你只“存储”第一种类型的值,第二种是幻像 。
But your Applicative
instance is only concerned with the second type variable that you have -- the b
, the elusive phantom. 但是你的
Applicative
实例只关注你拥有的第二个类型变量 - b
,难以捉摸的幻像。
That means that values like Constant (Sum 1)
can have any sort of thing as their second type variable -- it doesn't matter! 这意味着像
Constant (Sum 1)
这样的值可以将任何类型的东西作为它们的第二个类型变量 - 这无关紧要! You can write: 你可以写:
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)
Because you never actually need a value of the phantom type. 因为你实际上从未需要幻像类型的值。
Thus when you write Constant (Sum 1) <*> Constant (Sum 2)
, the type checker infers the correct types: 因此,当您编写
Constant (Sum 1) <*> Constant (Sum 2)
,类型检查器会推断出正确的类型:
let foo = Constant (Sum 1) :: Constant Sum (a -> b)
bar = Constant (Sum 2) :: Constant Sum a
in foo <*> bar
So the left-hand side of <*>
does have the type f (a -> b)
, but f
is Constant Sum
, not just Constant
. 所以
<*>
的左边确实有f (a -> b)
,但f
是Constant Sum
,而不仅仅是Constant
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.