变量列表构造函数,如何默认为正确的类型并获取类型安全性 [英] Variadic list constructor, how to default to the correct type and get type safety
本文介绍了变量列表构造函数,如何默认为正确的类型并获取类型安全性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
{ - #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
andListResultMult [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屋!
查看全文