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 }}
我的问题是为什么最后一个语句类型检查?
我预计&lt; *&gt;的左侧为f(a - > b)类型
凡
f =常数
(a - &gt; b)=总和1?
我无法应用于(总和1),因为它已完全应用,但此语句已编译。
答案 0 :(得分:4)
左侧是 f (a -> b)
。这是正确的。
请记住此处的类型(为简单起见,请设置1 :: Int
):
Constant (Sum 1) :: forall a. Constant (Sum Int) a
我添加了明确的forall
。类型检查器可以将a
与任何内容统一起来。
试试这个:
Constant (Sum 1) :: Constant (Sum Int) (a -> b)
工作正常。
答案 1 :(得分:4)
Const
:
(<*>) :: Const c (a -> b) -> Const c a -> Const c b
您的输入是Const c (a -> b)
和Const c a
。您提供Const c b
作为回报 - 如果x :: c
,则Const x :: Const c a
,任何a
。它可以是Const c Int
,Const c Bool
等。
例如:
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
所有类型检查,因为最后一个参数可以是任何内容 - "Hello"
仅约束第一个参数。
但是,您应该注意,Applicative
个实例并未遵守适用法律。
u <*> pure y = pure ($ y) <*> u
特别违反了:
Const "hello" <*> pure 4
== Const "hello" <*> Const ""
== Const ""
但
pure ($ 4) <*> Const "hello"
== Const "" <*> Const "hello"
== Const "hello"
答案 2 :(得分:3)
因为这里有两个类型变量:
public MyForm : base()
{
this.KeyPreview = true;
// handle KeyDown event
this.KeyDown += new KeyEventHandler(MyForm_KeyDown);
}
private void MyForm_KeyDown(object sender, KeyEventArgs e)
{
// do what you need
}
但你只是&#34;存储&#34;第一种类型的值,第二种是phantom。
但是您的newtype Constant a b =
Constant { getConstant :: a }
deriving (Eq, Ord, Show)
实例仅关注您拥有的第二个类型变量 - Applicative
,这是一个难以捉摸的幻像。
这意味着像b
这样的值可以作为第二个类型变量的任何东西 - 它并不重要!你可以写:
Constant (Sum 1)
因为你实际上从未需要幻影类型的值。
因此,当您编写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)
时,类型检查器会推断出正确的类型:
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
的左侧的类型为<*>
,但f (a -> b)
为 f
,而不仅仅是Constant Sum
。