Конструктор списков Variadic, как установить правильный тип по умолчанию и получить безопасность типов - PullRequest
6 голосов
/ 07 ноября 2011

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

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

Тип небезопасности:

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

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

  • Тип Безопасность.Я думал, что когда я определю ListResultMult r a => ListResultMult (a -> r) a и ListResultMult [a] a, это позволит вам создавать однородные списки и замечать ошибку типа, когда вы этого не сделаете. Почему не так?
  • По умолчанию.Я понятия не имею, что происходит со странностями listM 1 :: [Int]. Что случилось?

1 Ответ

6 голосов
/ 07 ноября 2011

Функции типа кажутся просто билетом для этой проблемы.Вот пример файла:

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

Вот ваши примеры в 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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...