Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将列表的内容用作单个多参数函数的位置参数_Haskell_Arguments - Fatal编程技术网

Haskell 将列表的内容用作单个多参数函数的位置参数

Haskell 将列表的内容用作单个多参数函数的位置参数,haskell,arguments,Haskell,Arguments,是否有一个标准的Haskell函数(或模式)来提取列表的内容并将其作为函数的有序位置参数提供 例如,考虑函数(/)>代码>,当给定两个位置参数时,将从它们中生成一个二元组: (,) 3 4 --> (3,4) 相反,假设我有一些无法更改的外部函数调用提供给我的参数,表示为列表[3,4] 是否有一个“内容”操作,使其能够工作: (,) $ contents_of [3, 4] 因此,的contents\u的行为就好像这些项被放置在源代码中,它们之间有空格作为函数应用程序一样 例如,[1]

是否有一个标准的Haskell函数(或模式)来提取列表的内容并将其作为函数的有序位置参数提供

例如,考虑函数<代码>(/)>代码>,当给定两个位置参数时,将从它们中生成一个二元组:

(,) 3 4 --> (3,4)
相反,假设我有一些无法更改的外部函数调用提供给我的参数,表示为列表
[3,4]

是否有一个“内容”操作,使其能够工作:

(,) $ contents_of [3, 4]
因此,的
contents\u的行为就好像这些项被放置在源代码中,它们之间有空格作为函数应用程序一样

例如,[1]
(,)$contents_应该是当前的函数
(,)1)
,然后再使用一个参数来完成元组的创建

我的一个想法是尝试将函数折叠到列表上,折叠函数表示currying:

foldr (\x y -> y x) (,) [3, 4]
但是看看foldr的类型签名:

foldr :: (a -> b -> b) -> b -> [a] -> b
这似乎很难做到<这里的code>b
需要是函数类型本身,但是当它被应用到参数时,它将不再是与
b
具有相同类型签名的函数,从而导致折叠中的类型问题

这在精神上类似于Python的
*args
构造


我不关心这可能意味着什么严格的属性——只关心在标准Haskell中是否可能出现类似的情况。

我通常使用如下匹配模式

let (a:b:c:_) = args
in  func a b c
或内联

(\(a:b:c:_) -> func a b c) args
如果您真的想这样做,您可以创建一个操作符来将“inyect”元素列表添加到任何函数中

showAdd2 <<< args
但您必须为每种情况选择适当的“inyector”

showAdd2 `i2` [4..5]

(在Haskell中,代数数据类型、列表和类的使用恰当地取代了对多变量函数的需求。正如@user5402所说,您应该提供一些明确的问题)

可以这样表示N元函数:

data FunN r a = FunN Int (a -> FunN r a) | FNil r
然后将普通函数转换为
FunN

f2FunN :: (FunN (a->b) a) -> FunN b a
f2FunN (FNil g)   = FunN 1 (FNil . g)
f2FunN (FunN n g) = FunN (n+1) (f2FunN . g)
然后应用参数列表:

a :: FunN b a -> [a] -> b
a (FNil r)   []    = r
a (FunN _ f) (x:t) = a (f x) t
a _          _     = error "wrong arity"
例如:

Prelude> a (f2FunN $ f2FunN $ FNil (+)) [1,2]
3
Prelude> a (f2FunN $ FNil (+)) [1] 2
3
Prelude> a (f2FunN $ f2FunN $ FNil (+)) [1,2,3]
*** Exception: wrong arity
Prelude> a (f2FunN $ f2FunN $ FNil (+)) [1]
*** Exception: wrong arity

但当然,您需要在编译时知道函数的算术性,这样您就可以知道可以用
f2FunN

包装函数多少次,正如我在上面的注释中所解释的,我认为这在标准列表中是不可能的。因此,让我们引入一个新的列表,其中列表中的每个元素都可以是不同的类型,并在列表的类型中进行编码:

{-# LANGUAGE GADTs, MultiParamTypeClasses, FlexibleInstances #-}

data Nil
data TList a b where
    TEmpty :: TList Nil Nil
    (:.) :: c -> TList d e -> TList c (TList d e)
infixr 4 :.
tenty
这里类似于
[]
:.
。所以我们可以有一个
Int
的列表,和几个
Bool
s:
31:。对:。错误:。诱惑
。此列表的类型为
tlistint(tlistbool(tlistbool(tlistnil-Nil))

现在,我们可以引入一个typeclass,它提供了一个函数,在类型匹配的情况下,该函数可以按照您提出的方式将任意函数应用于列表

class TApplies f h t r where
    tApply :: f -> TList h t -> r

instance TApplies a Nil Nil a where
    tApply a _ = a

instance TApplies f h t r => TApplies (a -> f) a (TList h t) r where
    tApply f (e :. l) = tApply (f e) l
我们现在可以使用
tApply
来做您想要做的事情。请注意,类似以下内容将无法编译:

tApply (+) $ 1 :. (2 :: Int) :. TEmpty
我们必须清楚地标注所有内容:

tApply ((+) :: Int -> Int -> Int) $ (1 :: Int) :. (2 :: Int) :. TEmpty :: Int
正如我们所期望的那样,这将提供
3
。我不知道如何避开这种需要;我希望巧妙地使用
功能依赖性可以达到目的。

为什么列表本身不起作用 从狭义上讲

是否有一个标准的Haskell函数(或模式)来提取列表的内容并将其作为函数的有序位置参数提供

这有一个非常简单的答案“不”。这种函数不存在的原因是类型签名不容易理解。您要求的类型签名是:

applyToList :: (a -> c) -> [a] -> d
其中,
c
要么具有形式
a->c'
(在这种情况下,我们递归定义),要么具有类型
d
。前奏曲函数都没有古怪的类型签名

如果您主动忽略此项并尝试,则会出现以下错误:

Prelude> let applyToList f list = case list of [] -> f; x : xs -> applyToList (f x) xs

<interactive>:9:71:
    Occurs check: cannot construct the infinite type: t1 ~ t -> t1
    Relevant bindings include
    xs :: [t] (bound at <interactive>:9:52)
    x :: t (bound at <interactive>:9:48)
    list :: [t] (bound at <interactive>:9:19)
    f :: t -> t1 (bound at <interactive>:9:17)
    applyToList :: (t -> t1) -> [t] -> t -> t1
        (bound at <interactive>:9:5)
    In the first argument of ‘applyToList’, namely ‘(f x)’
    In the expression: applyToList (f x) xs
然后,您可以编写如下内容:

wrap3 (\x y z -> (x + y) * z) `applyAll` [9, 11, 2]
它将正确地构造
40

正如您所知,这涉及到很多麻烦,但是有必要以完全通用的方式告诉编译器“嘿,这个函数将有三个参数,因此长度为3的列表非常适合它”

当然,编写
applyAll(wrap3\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但是,如果您试图构建具有任意算术运算的函数库,您可能可以使用一些额外的函数来为您管理这些算术运算


您可能还想用
Z
sz
等来注释列表的长度——在这种情况下,我想您可以得到一个
applyAll
,它可以进行转换。另外,正如另一个答案所指出的,如果有多个
Wrap
构造函数,可以将递归移到数据类型本身,这可能会让你有一个很好的距离——可能会删除一些讨厌的语言扩展。

如果没有依赖类型或大量扩展,就不可能编写真正的arity泛型函数,但你可以欺骗一点:

z :: b -> [a] -> b 
z x _ = x

s :: (b -> [a] -> c) -> (a -> b) -> [a] -> c
s h f (x:xs) = h (f x) xs
s _ _    _   = error "function called on too few arguments"

sum3 a b c   = a + b + c
tup4 a b c d = (a, b, c, d)

main = do
    print $ z               0    [1..4] -- 0
    print $ s (s (s z))     sum3 [1..4] -- 6
    print $ s (s (s (s z))) tup4 [1..4] -- (1, 2, 3, 4)
    -- print $ s (s (s (s z))) tup4 [1..3] -- runtime error
或者,如果要抛出错误,如果列表中的元素太多,则将
z
的定义更改为

z :: b -> [a] -> b 
z x [] = x
z _ _  = error "function called on too many arguments"

foldr
无法工作,因为它无法停止;我想函数的签名会变成编译时错误。是的,我提到过这一点。其他褶皱都有类似的问题。他们希望累加器的最终值的类型与其起始值相同,但中间货币函数将具有不同的类型。所以问题是,如果列表的长度超过了一个functi的参数数量,那么你不也会遇到类型问题吗
wrap3 (\x y z -> (x + y) * z) `applyAll` [9, 11, 2]
z :: b -> [a] -> b 
z x _ = x

s :: (b -> [a] -> c) -> (a -> b) -> [a] -> c
s h f (x:xs) = h (f x) xs
s _ _    _   = error "function called on too few arguments"

sum3 a b c   = a + b + c
tup4 a b c d = (a, b, c, d)

main = do
    print $ z               0    [1..4] -- 0
    print $ s (s (s z))     sum3 [1..4] -- 6
    print $ s (s (s (s z))) tup4 [1..4] -- (1, 2, 3, 4)
    -- print $ s (s (s (s z))) tup4 [1..3] -- runtime error
z :: b -> [a] -> b 
z x [] = x
z _ _  = error "function called on too many arguments"