繁体   English   中英

Haskell为什么这种类型检查

[英]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 }}

我的问题是为什么最后一个语句类型检查?

我希望<*>的左边是f(a - > b)类型
哪里
f =常数
(a - > b)=总和1?

我无法应用于(Sum 1),因为它已完全应用,但此语句编译。

左边 f (a -> b) 这是对的。

记住这里的类型(为简单起见,让我们创建1 :: Int ):

Constant (Sum 1) :: forall a. Constant (Sum Int) a

我添加了明确的forall 类型检查能够统一a任何事情。

试试这个:

Constant (Sum 1) :: Constant (Sum Int) (a -> b)

工作正常。

对于Const

(<*>) :: Const c (a -> b) -> Const c a -> Const c b

你的输入是一个Const c (a -> b)一个Const ca 你给了一个Const cb作为回报 - 如果x :: c ,那么Const x :: Const ca ,对于任何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"

因为这里有两个类型变量:

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) ,但fConstant Sum ,而不仅仅是Constant

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM