我正在使用#34; Haskell Programming from First Principles"这本书来学习Haskell,并且在第4章结束时,#34;基本数据类型",我已经遇到困扰我的事情。这本书提到了一个函数length
,并说它适用于Lists
。一切都很好,但当我尝试使用各种length
的{{1}}函数时,我看到的东西让我很困惑:
首先,让我们看一下Tuple
的类型:
length
好的,所以我在上面读到"带了一个Foldable,我认为这是一个方便的列表,并返回一个Int,即列表中元素的数量。"因此,我的第一个困惑:为什么以下工作:
:t length
length :: Foldable t => t a -> Int
因为对我而言,似乎我只是将带有两个元素的元组传递给length (1, 1)
1
,然后它返回1.是元组列表吗?元组是否可折叠?当然,为什么length
?
现在我更进一步:
1
另一次尝试:
length (1, 1, 1)
<interactive>:6:1:
No instance for (Foldable ((,,) t0 t1))
arising from a use of ‘length’
In the expression: length (1, 1, 1)
In an equation for ‘it’: it = length (1, 1, 1)
<interactive>:6:9:
No instance for (Num t0) arising from the literal ‘1’
The type variable ‘t0’ is ambiguous
Note: there are several potential instances:
instance Num Integer -- Defined in ‘GHC.Num’
instance Num Double -- Defined in ‘GHC.Float’
instance Num Float -- Defined in ‘GHC.Float’
...plus two others
In the expression: 1
In the first argument of ‘length’, namely ‘(1, 1, 1)’
In the expression: length (1, 1, 1)
<interactive>:6:12:
No instance for (Num t1) arising from the literal ‘1’
The type variable ‘t1’ is ambiguous
Note: there are several potential instances:
instance Num Integer -- Defined in ‘GHC.Num’
instance Num Double -- Defined in ‘GHC.Float’
instance Num Float -- Defined in ‘GHC.Float’
...plus two others
In the expression: 1
In the first argument of ‘length’, namely ‘(1, 1, 1)’
In the expression: length (1, 1, 1)
但是以下工作:
length (1::Int, 1::Int, 1::Int)
<interactive>:7:1:
No instance for (Foldable ((,,) Int Int))
arising from a use of ‘length’
In the expression: length (1 :: Int, 1 :: Int, 1 :: Int)
In an equation for ‘it’: it = length (1 :: Int, 1 :: Int, 1 :: Int)
对于我上面观察到的行为有什么好的解释吗?我误读了length (1::Int, 1::Int)
1
的类型吗?或者幕后还有其他事情发生了吗?
答案 0 :(得分:23)
你遇到了一个Haskell 导致célèbre,引发了很多讨论和咬牙切齿。
基本上,出于Foldable
(提供length
的类型类)的目的,2元组不被视为两个元素的容器,而是 one 的容器元素伴随着一些背景。
您可以从任何a
中提取Foldable a
类型的元素列表。请注意,对于2元组,Foldable
的类型变量是元组的 second 元素的类型变量,它可以与第一个元素的类型不同。
如果你有一个('c',2) :: (Char,Int)
元组,那么在这种情况下你无法提取两个Int
就不足为奇了!但是当类型相同时会变得混乱。
至于为什么length (1::Int, 1::Int, 1::Int)
失败,3元组没有定义Foldable
个实例,但为了保持一致,它们可能应该有一个Identity
实例。 3元组的长度也为1。
顺便说一下,Foldable
仿函数,可以被认为是一种1元组,也是Foldable
,当然也有长度为1。
元组的Execute sp_MSforeachtable
'Execute master.dbo.xp_cmdshell ''sqlcmd -S DATABASE -E -d mydb -q "SET NOCOUNT ON SELECT * FROM ?" -W -o C:\TEMP\?.bak -s "|"'''
实例是否存在 ?我认为赞成肯定的基本哲学是,我们称之为“充实”。如果类型可以以明确定义的合法方式成为类型类的实例,则应该具有该实例。即使它似乎没有用,在某些情况下,也可能令人困惑。
答案 1 :(得分:12)
我喜欢danidiaz的答案,因为它提供了关于元组的Foldable
实例如何工作以及它直观意味着什么的高层次直觉。然而,它的机制似乎仍然存在一些混乱;所以在这个答案中,我将重点关注&#34;幕后花絮&#34;位。相关Foldable
个实例的全文为available online,如下所示:
instance Foldable ((,) a) where
foldMap f (_, y) = f y
foldr f z (_, y) = f y z
您已经可以从这个实例中看到,在所有Foldable
方法中,每个元组的第一部分都被完全忽略。但是,要完成图片,我们需要查看minimum
和length
的定义。由于此实例不包含minimum
和length
的定义,因此我们应该查看这些定义的默认定义。 Foldable
的类声明看起来像这样(不相关的位被省略):
class Foldable t where
length :: t a -> Int
length = foldl' (\c _ -> c+1) 0
foldl' :: (b -> a -> b) -> b -> t a -> b
foldl' f z0 xs = foldr f' id xs z0
where f' x k z = k $! f z x
minimum :: forall a . Ord a => t a -> a
minimum = fromMaybe (error "minimum: empty structure") .
getMin . foldMap (Min #. (Just :: a -> Maybe a))
现在,让我们扩展这些定义,看看他们从哪里获得。
length (a, b)
= { definition of length }
foldl' (\c _ -> c+1) 0 (a, b)
= { definition of foldl' }
foldr (\x k z -> k $! (\c _ -> c+1) z x) id (a, b) 0
= { definition of foldr }
(\x k z -> k $! (\c _ -> c+1) z x) b id 0
= { beta reduction }
id $! (\c _ -> c+1) 0 b
= { id $! e = e }
(\c _ -> c+1) 0 b
= { beta reduction }
1
请注意,无论我们为a
和b
插入什么内容,结论都会成立。现在让我们做minimum
。出于我们的目的,我们将(#.)
替换为(.)
- 唯一的区别是效率,我们不关心这一特定推理线。
minimum (a, b)
= { definition of minimum }
( fromMaybe (error "minimum: empty structure")
. getMin
. foldMap (Min . Just)
) (a, b)
= { definition of (.) }
( fromMaybe (error "minimum: empty structure")
. getMin
) (foldMap (Min . Just) (a, b))
= { definition of foldMap }
( fromMaybe (error "minimum: empty structure")
. getMin
) ((Min . Just) b)
= { definition of (.) }
fromMaybe (error "minimum: empty structure")
(getMin (Min (Just b)))
= { definition of getMin }
fromMaybe (error "minimum: empty structure") (Just b)
= { definition of fromMaybe }
b