2011-11-06 13 views
6

Đây là những gì tôi đã có:variadic danh sách constructor, làm thế nào để mặc định đúng loại và nhận an toàn kiểu

{-# LANGUAGE MultiParamTypeClasses 
      , FlexibleInstances #-} 

class ListResultMult r a where 
    lstM :: a -> [a] -> r 

listM :: ListResultMult r a => a -> r 
listM a = lstM a [] 


instance ListResultMult r a => ListResultMult (a -> r) a where 
    lstM a as x = lstM x $ a:as 

instance ListResultMult [a] a where 
    lstM a as = reverse $ a:as 

Dưới đây là cách hoạt động:

> listM 'a' 'b' 'c' :: String 
"abc" 
> putStrLn $ listM 'a' 'b' 'c' 
abc 
> listM (1::Int) (2::Int) :: [Int] 
[1,2] 

Sau đây là cách nó không

> sum $ listM 1 2 
No instance for (ListResultMult (a2 -> [a0]) a1) ... 
> listM 1 :: [Int] 
No instance for (ListResultMult [Int] a0) ... 

Tương phản với printf:

instance Show a => ListResultMult (IO()) a where 
    lstM a as = print . reverse $ a:as 

> listM "foo" "bar" -- boo 
No instance for (ListResult t0 [Char]) ... 
> printf "%s %s" "foo" "bar" 
foo bar 
> listM "foo" "bar" :: IO() -- yay 
["foo","bar"] 

Loại mất an toàn:

> :t listM 2 "foo" 
Some weird type is actually inferred 

Vì vậy, đây là những gì tôi muốn làm:

  • Loại an toàn. Tôi nghĩ khi tôi xác định ListResultMult r a => ListResultMult (a -> r) aListResultMult [a] a, nó sẽ chỉ cho phép bạn tạo danh sách đồng nhất và nhận thấy lỗi loại khi bạn không làm như vậy. Tại sao không?
  • Mặc định. Tôi không có đầu mối gì đang xảy ra với listM 1 :: [Int]. Có chuyện gì vậy?

Trả lời

6

Chức năng loại dường như chỉ là vé cho vấn đề này. Đây là một tập tin mẫu:

{-# LANGUAGE TypeFamilies #-} 

class ListResultMult r where 
    type Elem r 
    lstM :: Elem r -> [Elem r] -> r 

listM a = lstM a [] 

instance (ListResultMult r, Elem r ~ a) => ListResultMult (a -> r) where 
    type Elem (a -> r) = a 
    lstM a as x = lstM x (a:as) 

instance ListResultMult [a] where 
    type Elem [a] = a 
    lstM a as = reverse (a:as) 

Dưới đây là ví dụ của bạn trong ghci:

*Main> listM 'a' 'b' 'c' :: String 
"abc" 
*Main> putStrLn $ listM 'a' 'b' 'c' 
abc 
*Main> listM 1 2 :: [Int] 
[1,2] 
*Main> sum $ listM 1 2 
3 
*Main> listM 1 :: [Int] 
[1] 
*Main> :t listM 'a' True 

<interactive>:1:7: 
    Couldn't match type `Bool' with `Char' 
    In the first argument of `listM', namely 'a' 
    In the expression: listM 'a' True 
*Main> :t listM 2 "foo" 

<interactive>:1:7: 
    No instance for (Num [Char]) 
     arising from the literal `2' 
    Possible fix: add an instance declaration for (Num [Char]) 
    In the first argument of `listM', namely `2' 
    In the expression: listM 2 "foo" 
+0

Loại an toàn * và * lành mạnh mặc định! Điều này trả lời câu hỏi một cách hoàn hảo, cũng như tình cờ trả lời [câu hỏi khác của tôi] (http://stackoverflow.com/questions/8031320). :) –