Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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_Variadic Functions_Function Parameter_Polyvariadic - Fatal编程技术网

如何创建多元haskell函数?

如何创建多元haskell函数?,haskell,variadic-functions,function-parameter,polyvariadic,Haskell,Variadic Functions,Function Parameter,Polyvariadic,我需要一个函数,它接受任意数量的参数(所有参数都是同一类型的),对它们进行处理,然后返回结果。在我的具体情况下,列出一系列的论点是行不通的 当我查看haskell库时,我看到函数printf(来自模块Text.printf)使用了类似的技巧。不幸的是,我无法通过查看源代码来理解这种魔力 有人能解释一下如何做到这一点,或者至少是一些网页/论文/任何我能找到好的描述的地方吗 动机: 我需要这个的原因其实很简单。对于学校(计算机科学课),我们需要编写一个模块,能够“记录”数学表达式,将其表示为字符串(

我需要一个函数,它接受任意数量的参数(所有参数都是同一类型的),对它们进行处理,然后返回结果。在我的具体情况下,列出一系列的论点是行不通的

当我查看haskell库时,我看到函数
printf
(来自模块
Text.printf
)使用了类似的技巧。不幸的是,我无法通过查看源代码来理解这种魔力

有人能解释一下如何做到这一点,或者至少是一些网页/论文/任何我能找到好的描述的地方吗

动机:

我需要这个的原因其实很简单。对于学校(计算机科学课),我们需要编写一个模块,能够“记录”数学表达式,将其表示为字符串(通过为自己的数据类型编写Num/Real/etc实例),并对其执行各种操作


此数据类型包含变量的特殊构造函数,该构造函数可以由值或任何指定函数替换。其中一个目标是编写一个函数,该函数使用一些变量(类型对
(Char,Rational)
)接受这样一个表达式,并计算表达式的结果。我们应该看看如何最好地表达函数的目标。(我的想法是:该函数返回另一个函数,该函数使用的参数与函数中定义的变量数量完全相同,这似乎是不可能的)。

在关于可变函数的wiki文章中被引用。我想printf就是这么做的,但我也不明白。无论如何,这肯定是一种过分的做法,尤其是因为您的参数都是同一类型的。把它们都放在一张单子上。这就是列表的好处——任意数量的相同类型的东西。很好,它不是很漂亮,但它几乎不会比一个完整的多变量函数更丑。

printf的关键点是能够返回字符串或函数。抄袭自

我们可以提取出的基本结构是

variadicFunction :: VariadicReturnClass r => RequiredArgs -> r
variadicFunction reqArgs = variadicImpl reqArgs mempty

class VariadicReturnClass r where
   variadicImpl :: RequiredArgs -> AccumulatingType -> r

instance VariadicReturnClass ActualReturnType where
   variadicImpl reqArgs acc = constructActualResult reqArgs acc

instance (ArgClass a, VariadicReturnClass r) => VariadicReturnClass (a -> r) where
   variadicImpl reqArgs acc = \a -> variadicImpl reqArgs (specialize a `mappend` acc)
例如:

class SumRes r where 
    sumOf :: Integer -> r

instance SumRes Integer where
    sumOf = id

instance (Integral a, SumRes r) => SumRes (a -> r) where
    sumOf x = sumOf . (x +) . toInteger
然后我们可以使用

*Main> sumOf 1 :: Integer
1
*Main> sumOf 1 4 7 10 :: Integer
22
*Main> sumOf 1 4 7 10 0 0  :: Integer
22
*Main> sumOf 1 4 7 10 2 5 8 22 :: Integer
59
我看了一下delnan引用的文章中的链接。盯着它看了一会儿,我想我终于明白了发生了什么:

它从以下类型类开始:

class BuildList a r  | r-> a where
    build' :: [a] -> a -> r
instance BuildList a [a] where
    build' l x = reverse$ x:l
管道后面的位(|)是函数依赖项。它表示由
a
表示的类型可以由
r
表示的类型确定。换句话说,您无法使用相同的
r
(返回类型),但不同的
a
定义
BuildList
类型类的两个实例

向前跳一点到实际使用
build'
函数的位置:

> build True :: [Bool]
由于
build
只是调用
build'
,第一个参数为空列表,这与:

> build' [] True :: [Bool]
在本例中,
build'
显然返回了一个列表。由于函数依赖性,我们只能绑定到
BuildList
type类的这个实例:

class BuildList a r  | r-> a where
    build' :: [a] -> a -> r
instance BuildList a [a] where
    build' l x = reverse$ x:l
很简单。第二个例子更有趣。扩展
build
的定义,它变成:

> build' [] True False :: [Bool]
在这种情况下,
build'
的类型是什么?Haskell的优先规则意味着上面也可以这样写:

> (build' [] True) False :: [Bool]
现在很清楚,我们正在将两个参数传递给
build'
,然后将该表达式的结果应用于值为“False”的参数。换句话说,表达式
(build'[]True)
应返回类型为
Bool->[Bool]
的函数。这将我们绑定到
BuildList
typeclass的第二个实例:

instance BuildList a r => BuildList a (a->r) where
    build' l x y = build'(x:l) y

在这个调用中,
l=[]
x=True
y=False
,因此定义扩展为
build'[True]False::[Bool]
。这个签名绑定到
build'
的第一个实例,它从哪里开始就相当明显。

很多人都在告诉你如何创建可变函数,但我认为在这种情况下,你实际上最好只使用类型[(Char,Rational)]的列表。

肯尼特的答案很好。下面是
sumOf 1 4 7 10::Integer
的exec过程示例,以提供更好的说明

sumOf 1 4 7 10
(( \ x -> ( sumOf . (x +) . toInteger ) 1 ) 4 7 10
((sumOf . (1 + ) . toInteger) 4 ) 7 10
( sumOf 5 ) 7 10
( sumOf . (5 + ) . toInteger ) 7 10
sumOf 12 10
sumOf . (12 + ) . toInteger 10
sumof 22
id 22
22

看看你的这个用例会很有趣。只是一些学校的项目。我会编辑这个问题并发布它的目的。你可以考虑其他的方法——一个列表的功能:评价:([(char,Rational)] -> EXPR->理性;取函数的函数:(Char->Rational)->Expr->Rational;获取映射的函数:Data.map.map Char Rational->Expr->Rational。请注意,使用这种可变函数意味着您模块的用户在其代码未键入check时将收到非常隐秘的错误消息。像“这不是一个列表”这样的错误比像“缺少PrintfType的实例…”这样的错误更容易理解。虽然这有点混乱,但这似乎就是我需要的。谢谢KennyTM!那正是我要找的@肯尼特:你知道吗,多元函数是否有标签?@fuzzxl:在这个网站上?有一个用于,但它是以C/C++为中心的。在C中它是不安全的(但从整体上讲,语言是不安全的),但在C++0x可变模板中允许类型安全的多变量函数。@FtheBuilder也许可以,但我想它与FlexibleInstances有关,一个数字不是一个具体的类型,而是一个
numa=>a
。这个描述非常简单,非常有用。我唯一不清楚的是定义
build'lx=reverse$x:l
。但在我看来,KennyTM的答案更有用,因为我更希望迭代参数,而不是将它们作为列表显示。请看,delnan已经说过了这一点。是的,我知道,这将是