Конструктор списка переменных, как установить по умолчанию правильный тип и обеспечить безопасность типа

Вот что у меня есть:

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

Вот как это работает :

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

Вот как это не удается

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

Сравните с 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"]

Тип unsafety:

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

Итак, вот что я хочу сделать:

  • Type Safety. Я думал, что когда я определил ListResultMult ra => ListResultMult (a -> r) a и ListResultMult [a] a , это позволит вам создавать только однородные списки и заметить введите ошибку, если вы этого не сделаете. Почему этого не произошло?
  • По умолчанию. Я понятия не имею, какие странности творится с listM 1 :: [Int] . Как дела?
6
задан Dan Burton 6 November 2011 в 23:40
поделиться