Jam*_*ong 3 haskell types functional-programming function semantics
我试图了解功能的类型并能够对其进行解释。
两个功能:
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)
Run Code Online (Sandbox Code Playgroud)
据我有限的知识,我认为插入功能:
insert
是类型t,它接受两个参数bool和一个类型t的两个列表的元组之一,并返回两个类型t的列表的元组。
partition
是类型t的元组,它返回布尔值,并且将类型t的列表作为其参数,并返回两个类型t的列表的元组。
这是正确的思考方式还是我做错了?我一直在关注一些教程,这是到目前为止我所做的。
Wil*_*sem 10
insert
是类型的t
,它需要两个参数之一Bool
和两个类型列表的元组之一,t
并返回两个类型列表的元组t
。
没有。首先,重要的是要注意,在Haskell中,每个函数都仅使用一个参数。确实
insert :: t -> Bool -> ([t],[t]) -> ([t],[t])
Run Code Online (Sandbox Code Playgroud)
是以下内容的简短形式:
insert :: t -> (Bool -> (([t],[t]) -> ([t],[t])))
Run Code Online (Sandbox Code Playgroud)
实际上,上面的内容还不是很详细,规范形式为:
insert :: ((->) t) (((->) Bool) (((->) ((,) ([] t)) ([] t)) ((,) ([] t)) ([] t)))
Run Code Online (Sandbox Code Playgroud)
但是上面的内容当然不是很可读,因此让我们坚持第二种形式。
Haskell中的每个函数都只使用一个参数。这里发生的是将参数应用于某个函数的结果生成了一个新函数。
因此,如果我们要生成一个表达式insert x
,我们就构造了一个类型的函数Bool -> (([t], [t]) -> ([t], [t]))
。
非正式地,确实有人有时说“一个函数需要n个参数 ”。但是,记住这一点很重要。
其次,您忘记了t
。我们可以非正式地说,insert
采用3点的参数,类型的值t
,一个boolean(型Bool
),和一个2元组的两个列表t
秒。它将返回一个2元组,其中包含t
s 的两个列表。根据Bool
is True
或False
it加上两个给定值的列表之一。
例如:
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])
Run Code Online (Sandbox Code Playgroud)
partition
是type的元组,t
它返回abool
,并接受type的列表t
作为参数,并返回两个type的列表的元组t
。
不,这里的参数的类型(t -> Bool)
为function。实际上,在Haskell中,您可以将函数作为参数传递。
可以非正式地说,它partition
接受一个“ 谓词 ”(一个将值映射到Bool
s 的函数)和一个t
s 列表,并返回一个带有两个t
s 列表的2元组。根据谓词是否包含列表中的值,这些值将在2元组的第一个或第二个列表中排序。
例如:
Prelude> partition (>3) [1,4,2,5]
([4,5],[1,2])
Prelude> partition (>3) [1,3,0,2]
([],[1,3,0,2])
Prelude> partition (>3) [1,7,8,0]
([7,8],[1,0])
Prelude> partition (>3) [1,7,8,9]
([7,8,9],[1])
Run Code Online (Sandbox Code Playgroud)
不,类型完全如所示:
insert
具有type t -> Bool -> ([t], [t]) -> ([t], [t])
,这意味着它是一个将type的值t
作为参数并返回type的函数的函数Bool -> ([t], [t]) -> ([t], [t])
。非正式地,您可以将其insert
视为一个带有3个参数的函数:一个类型t
,一个类型Bool
,一个类型([t], [t])
,然后返回另一个类型的值([t], [t])
。
partition
是一个将另一个函数(类型为t -> Bool
)作为参数的函数,并返回类型为的函数[t] -> ([t],[t])
。再次非正式地,您可以考虑partition
采用两个参数(type t -> Bool
和type [t]
)并返回type的值([t], [t])
。
->
本身是类型级别的运算符;它以两种类型作为参数并返回函数类型。它是右关联的,这意味着a -> (b -> c)
和a -> b -> c
是等效的。
不,insert
是一个函数,因此不能为“类型t
”。如果是类型t
,则将是一个值:
a :: Int
a = 5
Run Code Online (Sandbox Code Playgroud)
这a
是类型 Int
。
从函数实现中可以看到,insert
它带有三个参数:
insert a True (b,c) = ...
Run Code Online (Sandbox Code Playgroud)
该论点是a
,True
和(b, c)
。
因此,的类型insert
恰好是t -> Bool -> ([t],[t]) -> ([t],[t])
:
->
s)t
Bool -> ([t],[t]) -> ([t],[t])
Bool
(和Bool
只)([t],[t]) -> ([t],[t])
([t],[t])
(两个列表的元组,每个列表都包含某种类型的值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])
是类型 ([t],[t])
繁荣!最后一次调用实际上返回了一个值,而不是一个函数!因此,可以将其insert
视为三个参数的函数。这个东西叫做currying,它以Haskell被命名的那个人的名字命名-Haskell Curry。