Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a polyvariadic haskell function?

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).

like image 776
fuz Avatar asked Aug 12 '10 11:08

fuz


People also ask

What is <> called in Haskell?

It's an alias for mappend , from the Data. Monoid module.

How many arguments does a function have in Haskell?

Every function in Haskell officially only takes one parameter.

What is Haskell function?

Advertisements. Functions play a major role in Haskell, as it is a functional programming language. Like other languages, Haskell does have its own functional definition and declaration. Function declaration consists of the function name and its argument list along with its output.


2 Answers

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 
like image 114
kennytm Avatar answered Oct 15 '22 14:10

kennytm


KennyTM's answer is great. Below is an example of the exec process of sumOf 1 4 7 10 :: Integer to give a better illustration.

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
like image 21
lispc Avatar answered Oct 15 '22 15:10

lispc