Variadic list constructor, how to use the correct type by default and get the security type

Here is what I have:

{-# LANGUAGE MultiParamTypeClasses , FlexibleInstances #-} class ListResultMult ra where lstM :: a -> [a] -> r listM :: ListResultMult ra => a -> r listM a = lstM a [] instance ListResultMult ra => ListResultMult (a -> r) a where lstM a as x = lstM x $ a:as instance ListResultMult [a] a where lstM a as = reverse $ a:as 

Here's how it works:

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

That's how he fails

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

Contrast with 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"] 

Enter insecurity:

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

So here is what I want to do:

  • Type Security. I thought that when I defined ListResultMult ra => ListResultMult (a -> r) a and ListResultMult [a] a , it would only allow you to create homogeneous lists and notice a type error when you don't. Why wasn’t it?
  • Breaking. I do not know what is strange happening with listM 1 :: [Int] . What?
+6
source share
1 answer

Type functions seem like just a ticket for this problem. Here is an example 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" 
+6
source

Source: https://habr.com/ru/post/900902/


All Articles