如何创建一个polyvariadic haskell函数? [英] How to create a polyvariadic haskell function?

查看:172
本文介绍了如何创建一个polyvariadic haskell函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个接受任意数量参数(全部为相同类型)的函数,对它们做一些事情并在事后给出结果。在我的具体情况下,参数列表是不切实际的。

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



有人可以解释如何实现这一点,或者至少是某些网页/纸张/找到一个很好的描述?



动机:



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

这个数据类型包含一个变量的特殊构造函数,它可以被一个值或任何指定函数替代。其中一个目标是编写一个函数,该函数使用一些变量(类型为(Char,Rational))的变量,并计算表达式的结果。我们应该看看如何最好地表达功能的目标。 (我的想法:函数返回的函数与函数中定义的变量一样多 - 看来是不可能的)。

解决方案

div>

printf 的关键点是能够返回一个String或一个函数。从 http复制://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/src/Text-Printf.html

  printf ::(PrintfType r)=>字符串 - > r 
printf fmts = spr fmts []

class PrintfType t其中
spr :: String - > [UPrintf] - > t

实例(IsChar c)=> PrintfType [c]其中
spr fmts args = map fromChar(uprintf fmts(反向参数))

实例(PrintfArg a,PrintfType r)=> PrintfType(a - > r)其中
spr fmts args = \ a - > spr fmts(toUPrintf a:args)

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

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

class VariadicReturnClass r其中
variadicImpl :: RequiredArgs - > AccumulatingType - > r

instance VariadicReturnClass ActualReturnType其中
variadicImpl reqArgs acc = constructActualResult reqArgs acc

实例(ArgClass a,VariadicReturnClass r)=> VariadicReturnClass(a - > r)其中
variadicImpl reqArgs acc = \ a - >例如:

  class SumRes r其中
sumOf :: Integer - > r

实例SumRes整数其中
sumOf = id

实例(Integral a,SumRes r)=> SumRes(a - > r)其中
sumOf x = sumOf。 (x +)。 toInteger

然后我们可以使用

  *主> 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 ::整数
59


I need a function which takes an arbitrary number of arguments (All of the same type), does something with them and afterwards gives a result back. A list of arguments is impracticable in my specific case.

As I looked through the haskell libs, I saw that the function printf (from module Text.Printf) uses a similar trick. Unfortunately, I couldn't understand that magic by looking at the source.

Can somebody explain how to achieve this, or at least some webpage/paper/whatever where I could find a good description for this?

Motivation:

The reason I need this is really quite simple. For school (computer science class), we are required to write a module that is able to "record" a mathematical expression, express it as a string (Via writing an instance of Num/Real/etc for an own datatype), and perform various operations on it.

This datatype contains a special constructor for a variable, which may be replaced by a value or whatever by a specified function. One of the goals is to write a function, which takes such an expression with some number of variables (pairs of type (Char,Rational)) and calculates the result of the expression. We should look at how to express the goal of the function best. (My idea: The function returns another function which takes exactly as many arguments as vars that are defined in the function - seems to be impossible).

解决方案

The key points of printf is the ability to either return a String or a function. Copied from http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/src/Text-Printf.html,

printf :: (PrintfType r) => String -> r
printf fmts = spr fmts []

class PrintfType t where
    spr :: String -> [UPrintf] -> t

instance (IsChar c) => PrintfType [c] where
    spr fmts args = map fromChar (uprintf fmts (reverse args))

instance (PrintfArg a, PrintfType r) => PrintfType (a -> r) where
    spr fmts args = \a -> spr fmts (toUPrintf a : args)

and the basic structure we can extract out is

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)

For instance:

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

then we could use

*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

这篇关于如何创建一个polyvariadic haskell函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆