2012-02-22 84 views
15

异质列表我们可以利用对序列在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,()))) 

有没有一种方法,我们可以在这些列表上做类型级过滤?也就是说,定义一些多态函数hfilter例如,对于不同类型的ab,并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 *:() -> () 

回答

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 

现在我们可以通过显式定义我们想要的列表的类型来按类型过滤项目。

*Main> hfilter hlist :: [Int] 
[1,2] 
*Main> hfilter hlist :: [String] 
["hello"] 
*Main> hfilter hlist :: [Maybe Float] 
[Just 3.0] 
*Main> hfilter hlist :: [Maybe Int] 
[] 

它通过定义一个多参数类型级TypeFilter,这需要异质列表的类型,我们希望以滤除类型。然后,我们定义实例为空列表/单位()和一个列表,其中类型匹配(TypeFilter (t :* rest) t),最后一个列表,其中头部的类型不是我们要检索的类型不同(TypeFilter (a :* rest) t)

注在最后一个实例,目前还没有办法来表明at必须是不同的类型,但是当它们是相同的OverlappingInstances计数实例TypeFilter (t :* rest) t为更具体,在TypeFilter (a :* rest) t一个人选择它。

+0

对不起编译问题,我是从我的电话发帖。 – rampion 2012-02-22 14:44:43

+1

好吧,我可以从这里得到[通过传递过滤参数不需要'OverlappingInstances'的版本](https://gist.github.com/1885439)'hfilter :: a - > h - > h'',并为输出使用不同的列表。所以'hfilter(undefined :: Int)hlist ::()'是'()','hfilter(undefined :: Int)hlist :: Int:*()'是'1:*()'和'hfilter undefined :: Int)hlist :: Int:* Int:*()'是'1:* 2:*()'。 – rampion 2012-02-22 15:02:39

+0

arg,但需要'OverlappingInstances'来实际使用。 – rampion 2012-02-22 20:19:11

2

虽然存在方法去做你所要求的,你很可能没有在这里扮演Haskell的力量,你能详细说明一下吗?你需要什么?通常你可以枚举代数数据类型中需要的所有变体。您的列表将是同质的,允许您对元素进行模式匹配以对其进行操作。

+0

使用ADT,你可能会得到一个类似于['catMaybes']的解决方案(http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Maybe。 html#v:catMaybes),它通过特定的构造函数过滤列表。 – 2012-02-22 20:16:46

+0

我正在编写基于堆栈的DSL(有点类似因素)在haskell中 - 在这种情况下的异构列表是堆栈。 – rampion 2012-02-22 20:17:01

+1

啊,我想我明白了,也许是萨米的基于SNOC对的多态堆栈[在这里描述]的精神(https://github.com/leonidas/codeblog/blob/master/2012/2012-02-17- concatenative-haskell.md)? – 2012-02-23 08:29:19