2012-02-22 43 views
15

Chúng ta có thể sử dụng chuỗi cặp để tạo danh sách heterogenous trong Haskell:Haskell: lọc danh sách heterogenous theo loại

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,()))) 

Có cách nào chúng ta có thể làm lọc loại cấp trên các danh sách này? Đó là, xác định một số chức năng đa hình hfilter như vậy với nhiều loại khác nhau a, bc:

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 *:() -> () 

Trả lời

16

Có thể với một vài phần mở rộng loại (như là một sang một bên, hãy kiểm tra xem mã ví dụ của bạn biên dịch khi đăng câu hỏi. Tôi phải thực hiện một vài sửa đổi).

{-# 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 

Bây giờ, chúng tôi có thể lọc các mục theo loại bằng cách xác định rõ loại danh sách mà chúng tôi muốn.

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

Nó hoạt động bằng cách định nghĩa một đa tham số kiểu lớp TypeFilter, trong đó có các loại danh sách heterogenous và loại chúng tôi muốn lọc theo. Sau đó, chúng tôi xác định các trường hợp cho danh sách/đơn vị trống () và danh sách nơi loại phù hợp (TypeFilter (t :* rest) t) và cuối cùng cho danh sách có loại đầu khác với loại mà chúng tôi muốn truy xuất (TypeFilter (a :* rest) t).

rằng trong trường hợp cuối cùng hiện nay là không có cách nào để biểu thị rằng at phải loại khác nhau, nhưng khi họ đều giống nhau OverlappingInstances đếm sơ thẩm TypeFilter (t :* rest) t càng cụ thể hơn và chọn nó trên TypeFilter (a :* rest) t một.

+0

Xin lỗi về vấn đề biên dịch, tôi đã đăng bài từ điện thoại của mình. – rampion

+1

Ok, tôi đã có thể nhận được từ này để [một phiên bản mà không yêu cầu 'OverlappingInstances' bằng cách đi qua một đối số lọc] (https://gist.github.com/1885439)' hfilter :: a -> h - > h'' và sử dụng danh sách không đồng nhất cho đầu ra. Vì vậy, hfilter (undefined :: Int) hlist ::() 'là'() ',' hfilter (undefined :: Int) hlist :: Int: *() 'là' 1: *() 'và' hfilter (undefined :: Int) hlist :: Int: * Int: *() 'là' 1: * 2: *() '. – rampion

+0

arg, nhưng điều đó đòi hỏi 'OverlappingInstances' để thực sự sử dụng. – rampion

2

Mặc dù có tồn tại phương pháp để làm những gì bạn yêu cầu, có một xác suất rất cao mà bạn không chơi sức mạnh Haskell ở đây. Bạn có thể xây dựng o n nhu cầu của bạn? Thông thường bạn có thể liệt kê tất cả các biến thể mà bạn sẽ cần trong một kiểu dữ liệu đại số. Danh sách của bạn sau đó sẽ đồng nhất, cho phép bạn khớp mẫu trên các phần tử để hoạt động trên đó.

+0

Sử dụng ADT, có thể bạn sẽ kết thúc với một giải pháp tương tự về tinh thần đối với ['catMaybes'] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Maybe. html # v: catMaybes), bộ lọc này sẽ lọc danh sách theo một hàm tạo cụ thể. –

+0

Tôi đang chơi bằng cách viết một DSL dựa trên stack (yếu tố tương tự) trong haskell - danh sách không đồng nhất trong trường hợp này là ngăn xếp. – rampion

+1

ah, tôi nghĩ rằng tôi thấy, có thể một cái gì đó trong tinh thần của Samo SNOC-cặp dựa đa hình chồng [mô tả ở đây] (https://github.com/leonidas/codeblog/blob/master/2012/2012-02-17- concatenative-haskell.md)? –

Các vấn đề liên quan