变量列表构造函数,如何默认为正确的类型并获取类型安全性 [英] Variadic list constructor, how to default to the correct type and get type safety

查看:141
本文介绍了变量列表构造函数,如何默认为正确的类型并获取类型安全性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



  { - #LANGUAGE MultiParamTypeClasses 
,FlexibleInstances# - }

class ListResultMult ra其中
lstM :: a - > [a] - > r

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


实例ListResultMult r a => ListResultMult(a - > r)a其中
lstM a as x = lstM x $ a:as

实例ListResultMult [a] a其中
lstM a as =反向$ 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 
没有实例用于(ListResultMult(a2-> [a0])a1)...
> listM 1 :: [Int]
没有用于(ListResultMult [Int] a0)的实例...

与printf对比:

  instance显示a => ListResultMult(IO())a其中
lstM a as = print。反向$ a:as

> listMfoobar - boo
没有用于(ListResult t0 [Char])的实例...
> printf%s%sfoobar
foo bar
> listMfoobar:: IO() - yay
[foo,bar]

输入unsafety:

 > :t listM 2foo
一些奇怪的类型实际上被推断出来

想要做的:




  • 类型安全。我想当我定义 ListResultMult r a => ListResultMult(a - > r)a ListResultMult [a] a ,它只会允许您建立同类列表,并注意到如果没有,请键入错误。 为什么没有?

  • 默认。我不知道 listM 1 :: [Int] 有什么奇怪的事情发生。 发生了什么?


解决方案

对于这个问题。这是一个示例文件:

  { - #LANGUAGE TypeFamilies# - } 

class ListResultMult r其中
type Elem r
lstM :: Elem r - > [Elem r] - > r

listM a = lstM a []

实例(ListResultMult r,Elem r〜a)=> ListResultMult(a - > r)其中
类型Elem(a - > r)= a
lstM a as x = lstM x(a:as)

实例ListResultMult [a]其中
类型Elem [a] = a
lstM a as =反向(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'真正的

<互动>:1:7:
无法将'Bool'与'Char'匹配
在' listM',即'a'
在表达式中:listM'a'True
* Main> :t listM 2foo

< interactive>:1:7:
从字面值'2'$ b引起的(Num [Char])
没有实例$ b可能的修正:为(Num [Char])添加实例声明
在`listM'的第一个参数中,即'2'
在表达式中:listM 2foo


Here's what I've got:

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

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]

Here's how it 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"]

Type unsafety:

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

So here's what I want to do:

  • Type Safety. I thought when I defined ListResultMult r a => ListResultMult (a -> r) a and ListResultMult [a] a, it would only permit you to build up homogeneous lists, and notice a type error when you don't. Why didn't it?
  • Defaulting. I have no clue what weirdness is going on with listM 1 :: [Int]. What's up?

解决方案

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"

这篇关于变量列表构造函数,如何默认为正确的类型并获取类型安全性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆