我试图理解功能的类型并能够对其进行解释。
两个功能:
insert :: t -> Bool -> ([t],[t]) -> ([t],[t])
insert a True (b,c) = (a:b,c)
insert a False (b,c) = (b,a:c)
partition :: (t -> Bool) -> [t] -> ([t],[t])
partition p [] = ([],[])
partition p (x : xs) = insert x (p x) (partition p xs)
据我所知,我认为该插入功能:
insert
的类型为t,它接受两个参数bool和两个类型为t的两个列表的元组之一,并返回两个类型为t的列表的元组。
partition
是类型为t的元组,它返回一个布尔值,它以类型为t的列表作为参数,并返回两个类型为t的列表的元组。
是正确的思考方式还是我弄错了?我一直在关注一些教程,这是到目前为止我所做的。
答案 0 :(得分:10)
insert
的类型为t
,它接受两个参数Bool
和一个t
类型的两个列表的元组之一,并返回两个列表的元组类型t
。
否。首先,重要的是要注意,在Haskell中,每个函数都精确地 一个参数。确实
insert :: t -> Bool -> ([t],[t]) -> ([t],[t])
是以下内容的简短形式:
insert :: t -> (Bool -> (([t],[t]) -> ([t],[t])))
实际上,上面的内容还不是很详细,规范形式为:
insert :: ((->) t) (((->) Bool) (((->) ((,) ([] t)) ([] t)) ((,) ([] t)) ([] t)))
但是上面的内容当然不是很可读,因此让我们坚持第二种形式。
Haskell中的每个函数仅使用一个参数。这里发生的是将参数应用于某个函数的结果会生成一个新函数。
因此,如果我们要生成表达式insert x
,则我们构造了类型为Bool -> (([t], [t]) -> ([t], [t]))
的函数。
非正式地,有时确实有人说“ 函数需要n个参数”。但是记住这一点很重要。
其次,您忘记了t
。我们可以非正式地说insert
接受三个参数,一个t
类型的值,一个布尔值(Bool
类型)和一个带有两个列表的2元组的t
个。它将返回一个包含t
的两个列表的2元组。根据{{1}}是Bool
还是True
的不同,它会给两个列表之一添加给定值。
例如:
False
Prelude> insert 5 False ([], []) ([],[5]) Prelude> insert 5 False ([1,4], [2,5]) ([1,4],[5,2,5]) Prelude> insert 5 True ([1,4], [2,5]) ([5,1,4],[2,5]) Prelude> insert 3 True ([1,4], [2,5]) ([3,1,4],[2,5]) Prelude> insert 3 False ([1,4], [2,5]) ([1,4],[3,2,5])
是类型partition
的元组,它返回t
,它接受类型bool
的列表作为参数,并返回两个列表的元组输入t
。
否,此处的参数具有类型为t
的功能。确实,在Haskell中,您可以将函数作为参数传递。
我们可以说(t -> Bool)
带有一个“ 谓词”(一个将值映射到partition
的函数)和一个Bool
的列表,并返回一个包含两个t
列表的2元组。根据谓词是否保留列表中的值,这些值将在2元组的第一个或第二个列表中排序。
例如:
t
答案 1 :(得分:6)
否,类型完全相同:
insert
的类型为t -> Bool -> ([t], [t]) -> ([t], [t])
,这意味着它是一个将类型为t
的值作为参数并返回类型为Bool -> ([t], [t]) -> ([t], [t])
的函数。非正式地,您可以将insert
视为一个带有3个参数的函数:一个类型为t
,一个类型为Bool
和一个类型为([t], [t])
,并返回另一个类型([t], [t])
的值。
partition
是一个以另一个函数(类型为t -> Bool
)作为参数的函数,并返回类型为[t] -> ([t],[t])
的函数。再次非正式地,您可以将partition
视为接受两个参数(类型为t -> Bool
和类型[t]
)并返回类型为([t], [t])
的值。
->
本身是类型级别的运算符;它以两种类型作为参数并返回函数类型。它是右关联的,这意味着a -> (b -> c)
和a -> b -> c
是等效的。
答案 2 :(得分:5)
否,insert
是函数,因此不能为“ t
类型”。如果类型为t
,则它将是 value :
a :: Int
a = 5
a
是类型的 Int
。
从函数实现中可以看到,insert
接受三个参数:
insert a True (b,c) = ...
参数为a
,True
和(b, c)
。
因此,insert
的类型恰好是t -> Bool -> ([t],[t]) -> ([t],[t])
:
->
个原因t
的个参数的Bool -> ([t],[t]) -> ([t],[t])
的另一个函数
Bool
(仅Bool
)的一个参数 ([t],[t]) -> ([t],[t])
([t],[t])
类型的参数(两个列表的元组,每个列表包含 some 类型的值{ {1}})t
现在,这看起来像是一团糟:函数返回其他函数,这些函数返回函数...但这可以简化。您可以将([t],[t])
视为三个参数的函数:
insert
是一个疯狂的函数,它返回其他函数:键入insert
t -> Bool -> ([t],[t]) -> ([t],[t])
的类型为insert 2
Bool -> ([t],[t]) -> ([t],[t])
,如果类型为insert 2 True
([t],[t]) -> ([t],[t])
的类型为insert 2 True ([1], [2])
BOOM!最后一次调用实际上返回了一个值,而不是一个函数!因此,可以将([t],[t])
视为三个参数的函数。这个东西叫做currying,它以Haskell被命名的那个人的名字命名-Haskell Curry。