Haskell为什么这种类型检查

时间:2016-01-09 22:19:51

标签: haskell types

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),因为它已完全应用,但此语句已编译。

3 个答案:

答案 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 IntConst 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

相关问题