簡體   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