Haskell语言学习笔记(97)Phantom Type
示例
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module NamedTypeclass where
import Prelude hiding (Monoid, mempty, (<>))
data Sum
data Product
class Monoid b a where
(<>) :: a -> a -> a
mempty :: a
instance Monoid Sum Int where
x <> y = x + y
mempty = 0
instance Monoid Product Int where
x <> y = x * y
mempty = 1
instance Monoid b [a] where
x <> y = x ++ y
mempty = []
fold :: forall b a . Monoid b a => [a] -> a
fold [] = mempty @b
fold (x : xs) = (<>) @b x (fold @b xs)
sum :: [Int] -> Int
sum = fold @Sum
product :: [Int] -> Int
product = fold @Product
concat :: [[a]] -> [a]
concat = fold
*NamedTypeclass> NamedTypeclass.sum [1,2,3,4]
10
*NamedTypeclass> NamedTypeclass.product [1,2,3,4]
24
*NamedTypeclass> NamedTypeclass.concat [[1],[2]]
[1,2]
Phantom Type
Phantom type
WHAT I WISH I KNEW WHEN LEARNING HASKELL - Phantom Types
AllowAmbiguousTypes
{-# LANGUAGE AllowAmbiguousTypes #-}
允许类型签名中的类型不出现在定义中,此时该类型为模糊(Ambiguous)类型,而所定义的类型被称为虚无(Phantom)类型。
示例中
class Monoid b a
的 b 就没有出现在定义中,因而 b 是模糊类型,Monoid 是虚无类型。
Empty Type
示例中
data Sum
该类型没有实体,是 Empty Type。
MultiParamTypeClasses
{-# LANGUAGE MultiParamTypeClasses #-}
允许类型类的定义中包含一个以上的参数。
示例中
class Monoid b a
的类型签名中含有两个类型参数 b 和 a。
FlexibleInstances
{-# LANGUAGE FlexibleInstances #-}
允许类型实例的类型签名中包含类型别名或嵌套类型。
示例中
instance Monoid b [a]
的类型签名中含有嵌套类型 [a]。
ExplicitForAll
{-# LANGUAGE ExplicitForAll #-}
允许显式使用 forall
ScopedTypeVariables
{-# LANGUAGE ScopedTypeVariables #-}
允许 forall 所引进的类型变量用作类型修饰。
示例中
fold :: forall b a . Monoid b a => [a] -> a
的类型签名中 forall 所声明的两个类型参数 b 和 a。
TypeApplications
{-# LANGUAGE TypeApplications #-}
允许使用类型应用程序(Type Application)的语法。
使用 TypeApplications 可以将某个多态函数应用到某个具体类型上(该类型前需要加上 @)
相当于在别的语言中调用泛型函数时指定类型参数。
Prelude> :set -XTypeApplications
Prelude> show (read @Int "5")
"5"
示例中
sum = fold @Sum
将 fold 函数的类型变量 b 指定为类型实例 Sum