Variadic list constructor, how to default to the correct type and get type safety

后端 未结 1 1819
不知归路
不知归路 2021-01-05 11:31

Here\'s what I\'ve got:

{-# LANGUAGE MultiParamTypeClasses
           , FlexibleInstances #-}

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

         


        
相关标签:
1条回答
  • 2021-01-05 12:14

    Type functions seem like just the ticket for this problem. Here's a sample file:

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

    Here are your examples in 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 讨论(0)
提交回复
热议问题