2012-02-22 80 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