List zip函数还需要第二个列表,如何仅使用一个参数列表
我开始学习Haskell,并找到了一个很好的锻炼方法。以下是:List zip函数还需要第二个列表,如何仅使用一个参数列表,list,haskell,currying,partial-application,List,Haskell,Currying,Partial Application,我开始学习Haskell,并找到了一个很好的锻炼方法。以下是: grouping: Int -> [Student]->[(Team, Student)] grouping teamNumber = zip ys where ... grap :: Int -> [a] -> [a] grab _ [] = [] grab n (x:xs) = if n <= 0 then [] else x : grab (n-1)
grouping: Int -> [Student]->[(Team, Student)]
grouping teamNumber = zip ys
where ...
grap :: Int -> [a] -> [a]
grab _ [] = []
grab n (x:xs) = if n <= 0 then [] else x : grab (n-1) xs
infinite :: Num a => a -> [a]
infinite x = x : infinite(x+1)
所以,这个练习想让我试着填满剩下的部分。该函数应执行以下操作:
示例:分组2['Mark'、'Hanna'、'Robert'、'Mike'、'Jimmy']=[(1,'Mark')、(2,'Hanna')、(1,'Robert')、(2,'Mike')、(1,'Jimmy')]
因此,我们正在组建由两名学生组成的团队,最后一名学生“吉米”没有队友
然后,我还查找预定义函数zip
的作用。它获取两个列表参数,并将列表的每个元素连接到一个元组以构建元组列表
我的想法是:
1) 我尝试构建两个函数“抓取”和“无限”。他们的情况如下:
grouping: Int -> [Student]->[(Team, Student)]
grouping teamNumber = zip ys
where ...
grap :: Int -> [a] -> [a]
grab _ [] = []
grab n (x:xs) = if n <= 0 then [] else x : grab (n-1) xs
infinite :: Num a => a -> [a]
infinite x = x : infinite(x+1)
因此,xs
现在是我的第一个zip
列表,尤其是整数列表
但是现在我的问题是:zip
作为预定义函数还需要第二个列表,特别是学生姓名的列表,但是在给定的函数中,他们只给zip一个参数,即作为列表的ys
。我怎么能理解呢?分组组号的类型`
仔细查看分组::Int->[Student]->[(团队,学生)]
的类型,以及为其声明而声明的参数
grouping :: Int -> [Student]->[(Team, Student)]
grouping teamNumber = ...
如果在等号左侧列出的所有参数中都提供了grouping
则返回类型是什么(等号右侧的类型)
答复
等号右侧的类型是
[Student]->[(团队,学生)]
。在Haskell中,接受两个参数并返回结果的函数可以等价地看作或定义为接受第一个参数并返回结果的函数(接受第二个参数并返回结果的函数)。例如,我们可以说,表达式
grouping 3 :: [Student]->[(Team, Student)]
(分组3)
是一个函数,它获取学生列表并返回这些学生的列表,标记为3个组。假设将(第3组)
应用于您示例中的学生列表,我们将
(grouping 3) [ 'Mark' , 'Hanna' , 'Robert' , 'Mike' , 'Jimmy' ] =
[(1,'Mark'),(2,'Hanna'),(3,'Robert'),(1,'Mike'),(2,'Jimmy')]
zip-ys的类型`
咖喱与以下类型和表达式有什么关系
zip :: [a] -> [b] -> [(a, b)]
zip ys
例如,如果ys:[Bool]
,zip ys的类型会是什么
这和你的问题有什么关系
当你考虑这与“代码”类型分组“团队编号< /代码>”时,这是如何告诉你在练习中需要使用<代码> ys>代码>的类型?< /p> 把它们放在一起 从练习代码(忽略类型和
where
子句)中,我们有:
只有在Haskell中将两种类型统一起来的情况下,才能将它们定义为=
。在这种情况下,分组组号
的类型必须与zip ys
的类型统一
从第一部分,我们知道分组组号的类型是[Student]->[(Team,Student)]
从第二部分,我们知道zip ys
具有类型[b]->[(a,b)]
,其中a
是一种类型,使得ys
具有类型[a]
因此,我们知道(~
在Haskell中是类型相等的)
如果我们用以下变量替换类型变量b
和a
b ~ Student
a ~ Team
现在,我们知道ys
的类型是[a]
,如果我们进行相同的替换,它就是[Team]
因此,如果ys::[Team]
,则类型将是正确的
结论
如果您可以提供一个
ys::[Team]
,您可以通过将ys
作为第一个参数传递给zip
,从学生到被标记为其团队的学生([Student]->[(Team,Student)]
)生成一个函数。这样的函数正是分组
应用于单个参数时需要返回的函数,teamNumber::Int
当您第一次遇到它时,Currying可能会有点混乱。基本上是这样的(我将忽略一些技术细节)
基本概念是:在Haskell中,每个函数只接受一个参数。如果要模拟具有两个参数的函数,有两种方法:
多元组
您可以编写一个接受元组的函数。这是标准ML中的常规方法,但通常仅在Haskell中使用,尤其是在最明智的情况下:
distanceFromOrigin :: (Double, Double) -> Double
distanceFromOrigin (x, y) = sqrt (x^2 + y^2)
咖喱
您可以编写一个curried函数。curry背后的概念是,当你将一个函数应用于一个参数时,你可以得到另一个函数,它接受第二个参数。首先,我将使用lambda表示法非常明确地写出:
product :: Double -> (Double -> Double)
product x = \y -> x * y
假设我从(产品3)4
开始。我可以先减少(产品3)
以获得
(\y -> 3 * y) 4
然后我可以完成这项工作,得到12分
Haskell提供了一些语法来帮助解决这类问题。首先,它让我写作
product x y = x * y
意指
product x = \y -> x * y
其次,它使函数应用程序左关联,因此我可以编写product 3 4
,意思是(product 3)4
最后,它使
->
类型构造函数具有右关联性,因此我可以编写product::Double->Double->Double
,而不是在Haskell中编写product::Double->(Double->Double)
,以下内容是等效的:
f = (\x y -> ..x..y.. )
f = (\x -> (\y -> ..x..y.. )) -- this equivalence is known as "currying"
f x = (\y -> ..x..y.. ) -- partially applying f with x gives (\y->...)
f x y = ..x..y..
((\x->…)
当然是Haskell对匿名的表示法,即所谓的“lambda”函数(\
是希腊字母λ的提醒)
在Haskell中,函数与其他值一样,因此函数调用或“函数指针”等没有特殊的语法。对于类型,上述自然需要
f :: a -> b -> t
f x :: b -> t -- the result of calling f w/ x (of type a) has type b->t
f x y :: t -- when f :: a->b->t, x :: a, y :: b, then f x y :: t
盯着它看一会儿
这就是咖喱。函数调用仅由并置表示
f :: a -> b -> t
f x :: b -> t -- the result of calling f w/ x (of type a) has type b->t
f x y :: t -- when f :: a->b->t, x :: a, y :: b, then f x y :: t