In Haskell, are “higher-kinded types” *really* types? Or do they merely denote collections of *concrete* types and nothing more?

后端 未结 2 641
栀梦
栀梦 2021-02-05 16:39

Paramametrically polymorphic functions

Consider the following function:

f :: a -> Int
f x = (1 :: Int)

We might say that the type

2条回答
  •  无人共我
    2021-02-05 17:11

    First a question: Is the statement "all lists have length" a single statement or a series of statements "list1 has length", "list2 has length",...?

    If you give the type of f with explicit forall, you get f :: forall a. a -> Int. First of all, this is not "higher-kinded". We can do the following in GHCI:

    λ> :set -XRankNTypes
    λ> :k (forall a. a -> Int)
    (forall a. a -> Int) :: *
    

    So f has a kind of *.

    Now, in Haskell, we can use ~ for type equality. We can set the following to check stuff in GHCI:

    λ> :set -XImpredicativeTypes
    λ> :set -XTypeFamilies
    λ> :t undefined :: ((~) Int Int) => a
    undefined :: ((~) Int Int) => a :: a
    

    This shows that GHC figured out type equality for this example. Type inequality will give the following error:

    λ> undefined :: ((~) (Int -> Int) (Int)) => a
    
    :22:1:
        Couldn't match expected type ‘Int’ with actual type ‘Int -> Int’
        In the expression: undefined :: ((~) (Int -> Int) (Int)) => a
        In an equation for ‘it’:
        it = undefined :: ((~) (Int -> Int) (Int)) => a
    

    Now using this method directly will prevent us from comparing the type of f, but I found a slight variant that should work for our purposes:

    λ> :t undefined :: forall a. ((a -> Int) ~ (Int -> Int)) => a
    undefined :: forall a. ((a -> Int) ~ (Int -> Int)) => a :: Int
    

    In other words, if f is type-equivalent to g :: Int -> Int, then a must be Int. This is similar to x = y, y = 0 so x = 0. We don't have x = 0 until we specify y = 0, until then we just have x = y.

    Maybe is different because it has the following kind:

    λ> :k Maybe
    Maybe :: * -> *
    

    Because we're using DataKinds, we have :k (~) :: k -> k -> GHC.Prim.Constraint, so we can do things like:

    λ> :t undefined :: (~) Maybe Maybe => Int
    undefined :: (~) Maybe Maybe => Int :: Int
    
    λ> :k Either ()
    Either () :: * -> *
    
    λ> :t undefined :: (~) Maybe (Either ()) => Int
    Couldn't match expected type ‘Either ()’ with actual type ‘Maybe’
    

    To sum up, f :: forall a. a -> Int makes as much sense as the statement "if you give me anything, I'll give you an Int". Could you translate the statement into a bunch of statements "if you give me a dog..", "if you give me a penny.."? Yeah, but it weakens the statement. At the end, decide precisely what you mean by the "same" and you get your answer.

提交回复
热议问题