我们可以使用对序列在Haskell中创建异构列表:
type a *: b = (a, b)
a *: b = (a, b)
infixr 5 *:
hlist :: Int *: String *: Maybe Float *: ()
hlist = 1 *: "hello" *: Just 3 *: () -- (1, ("hello", (Just 3, ())))
Run Code Online (Sandbox Code Playgroud)
有没有办法可以对这些列表进行类型级别过滤?也就是说,定义一些多态函数hfilter,例如,对于不同类型a,b以及c:
hfilter :: a *: b *: c *: a *: b *: a *: () -> a *: a *: a *: ()
hfilter :: a *: b *: c *: a *: b *: a *: () -> b *: b *: ()
hfilter :: a *: b *: c *: a *: b *: a *: () -> c *: ()
hfilter :: a *: b *: c *: a *: b *: a *: () -> ()
Run Code Online (Sandbox Code Playgroud)
sha*_*ang 16
可以使用一些类型扩展(另外,请在发布问题时检查您的示例代码是否已编译.我必须进行相当多的更正).
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE OverlappingInstances #-}
type a :* b = (a, b)
a *: b = (a, b)
infixr 5 *:
infixr 5 :*
hlist :: Int :* String :* Int :* Maybe Float :* ()
hlist = 1 *: "hello" *: 2 *: Just 3 *: ()
class TypeFilter lst t where
hfilter :: lst -> [t]
instance TypeFilter () t where
hfilter _ = []
instance TypeFilter rest t => TypeFilter (t :* rest) t where
hfilter (a, rest) = a : hfilter rest
instance TypeFilter rest t => TypeFilter (a :* rest) t where
hfilter (_, rest) = hfilter rest
Run Code Online (Sandbox Code Playgroud)
现在我们可以通过显式定义所需列表的类型来按类型过滤项目.
*Main> hfilter hlist :: [Int]
[1,2]
*Main> hfilter hlist :: [String]
["hello"]
*Main> hfilter hlist :: [Maybe Float]
[Just 3.0]
*Main> hfilter hlist :: [Maybe Int]
[]
Run Code Online (Sandbox Code Playgroud)
它的工作原理是定义一个多参数类型类TypeFilter,它采用异构列表的类型和我们想要过滤的类型.然后,我们为空列表/单元()和类型匹配(TypeFilter (t :* rest) t)的列表定义实例,最后为头部类型不同于我们要检索的类型的列表定义实例(TypeFilter (a :* rest) t).
请注意,在最后一个实例中,目前没有办法表示它,a并且t必须是不同的类型,但是当它们相同时,OverlappingInstances将实例计TypeFilter (t :* rest) t为更具体,并选择它TypeFilter (a :* rest) t.