
Is it possible to write a function like this: zipn n list_1 list_2 list_3 ... list_n which implements zip3 for n=3, zip4 for n=4 etc.? Looks like variable number of arguments are possible, like printf shows, so a general zipn should be possible, too. If it is possible, why there are functions like zip5 and not just zipn? -- Frank Buss, fb@frank-buss.de http://www.frank-buss.de, http://www.it4-systems.de

Frank, The return type of zipn would have to depend on the number of arguments. If you are satisfied with all arguments having the same type, then you can use transpose: zipn list1 list2 .. listn => transpose [list1, list2, .. listn] Can we make a polyvariadic zipn that returns a [HList]? Seems like a neat challenge, but I'm a bit pressed for time right now. I'm afraid it would be pretty unwieldy. I'm looking forward to seeing solutions though. :-) -- Joel

I was looking for something like this too. Note that Erlang can do this ;-) but Erlang is probably not so strongly typed, so it's easier to do?

On Sat, Aug 11, 2007 at 05:27:19PM +0800, Hugh Perkins wrote:
I was looking for something like this too.
Note that Erlang can do this ;-) but Erlang is probably not so strongly typed, so it's easier to do?
I think the main issue is that Erlang doesn't use currying (IIRC). Currying makes it MUCH harder to implement varargs functions. (We thought this was a good tradeoff - partial applications give Haskell much more power than varargs would have.) (Unfortunately I don't know of any good languages with powerful type systems and vararg functions that can take advantage of powerful types... I'd love to give example code here :)) Stefan

On Sun, Aug 12, 2007 at 12:56:31PM +1000, Alexis Hazell wrote:
On Sunday 12 August 2007 05:24, Stefan O'Rear wrote:
Currying makes it MUCH harder to implement varargs functions.
That's interesting - why is that the case?
varsum 2 3 -- varsum receives 2, and returns a function, which when -- passed 3, returns 5 varsum 2 3 4 -- varsum receives 2, and returns a function, which when -- passed 3, returns a function that when passed 4 returns -- 9. Because of this, the number of arguments must somehow be passed out-of-band; but then the type of the whole function (usually) must depend on the control parameter, requiring dependent types. Stefan

Hi Stefan I'd have my membership of the one-leg club taken away if I didn't write in and say that,... On 12 Aug 2007, at 04:25, Stefan O'Rear wrote:
On Sun, Aug 12, 2007 at 12:56:31PM +1000, Alexis Hazell wrote:
On Sunday 12 August 2007 05:24, Stefan O'Rear wrote:
Currying makes it MUCH harder to implement varargs functions.
...while I wouldn't disagree,...
That's interesting - why is that the case?
varsum 2 3 -- varsum receives 2, and returns a function, which when -- passed 3, returns 5 varsum 2 3 4 -- varsum receives 2, and returns a function, which when -- passed 3, returns a function that when passed 4 returns -- 9.
...this is one of the more elementary exercises in overloading...
Because of this, the number of arguments must somehow be passed out-of-band;
...the type...
but then the type of the whole function (usually) must depend on the control parameter, requiring dependent types.
...of dependent walk you can mimic by hopping in Haskell.
module VarSum where
class VarSum t where varacc :: Int -> t
varsum :: VarSum t => t varsum = varacc 0
type Z = Int type S = (->) Int
instance VarSum Z where varacc a = a
instance VarSum t => VarSum (S t) where varacc a b = varacc (a + b)
Of course, you have to say stuff like varsum (2 :: Int) (3 :: Int) :: Int to determine the type at which the overloading happens. Or perhaps (varsum :: S (S Z)) 2 3 But there am I, proving your point. In Haskell, this sort of thing is a stunt. I'd much rather it was boring. All the best Conor

Frank Buss schrieb:
Is it possible to write a function like this:
zipn n list_1 list_2 list_3 ... list_n
which implements zip3 for n=3, zip4 for n=4 etc.? Looks like variable number of arguments are possible, like printf shows, so a general zipn should be possible, too. If it is possible, why there are functions like zip5 and not just zipn?
What type would this function have? It's not possible to formulate this type in Haskell98. The problem is that the number of arguments cannot be determined statically, i.e. it depends on the value of n at run-time. There are languages more freaky than Haskell (like Agda or Epigram ) that can do that (without dynamic typing, that is!), they are called "dependently typed". However, type-class hackery (or type synonym families once they're available in GHC) can be used to do something like that if you give the value of n at compile-time. I won't dwell into that, though. Also, applicative functors can help GHCi> :m +Control.Applicative GHCi> (\x y z -> x*(y+z)) <$> ZipList [1,2,3] <*> ZipList [-1,0,1] <*> ZipList [1,1,1] ZipList [0,2,6] GHCi> (the second command is a single line.) Regards, apfelmus

On 8/11/07, apfelmus
Frank Buss schrieb:
Is it possible to write a function like this:
zipn n list_1 list_2 list_3 ... list_n
which implements zip3 for n=3, zip4 for n=4 etc.? Looks like variable number of arguments are possible, like printf shows, so a general zipn should be possible, too. If it is possible, why there are functions like zip5 and not just zipn?
What type would this function have? It's not possible to formulate this type in Haskell98. The problem is that the number of arguments cannot be determined statically, i.e. it depends on the value of n at run-time. There are languages more freaky than Haskell (like Agda or Epigram ) that can do that (without dynamic typing, that is!), they are called "dependently typed".
However, type-class hackery (or type synonym families once they're available in GHC) can be used to do something like that if you give the value of n at compile-time. I won't dwell into that, though.
Also, applicative functors can help
GHCi> :m +Control.Applicative GHCi> (\x y z -> x*(y+z)) <$> ZipList [1,2,3] <*> ZipList [-1,0,1] <*> ZipList [1,1,1] ZipList [0,2,6] GHCi>
(the second command is a single line.)
Applicative functors can indeed help: (,,,) <$> [1,2,3] <*> [-1,0,1] <*> [1,1,1] <*> [0,2,6] You just use n-1 commas when you want the effect of zipn. -Per

On 8/11/07, Per Vognsen
Applicative functors can indeed help:
(,,,) <$> [1,2,3] <*> [-1,0,1] <*> [1,1,1] <*> [0,2,6]
You just use n-1 commas when you want the effect of zipn.
Actually, that's not quite right, since that uses the applicative functor related to the list monad (so you get a list of 4-tuples of all possible combinations, rather than a 4-way zip). To get the zip behavior, you need to add a ZipList constructor in front of all the lists, and then apply getZipList at the end to extract. -Brent

Also, applicative functors can help
GHCi> :m +Control.Applicative GHCi> (\x y z -> x*(y+z)) <$> ZipList [1,2,3] <*> ZipList [-1,0,1] <*> ZipList [1,1,1] ZipList [0,2,6] GHCi> http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf quote "The general scheme is as follows:" (page 2)
Marc

On 8/11/07, Frank Buss
Is it possible to write a function like this:
zipn n list_1 list_2 list_3 ... list_n
which implements zip3 for n=3, zip4 for n=4 etc.? Looks like variable number of arguments are possible, like printf shows, so a general zipn should be possible, too. If it is possible, why there are functions like zip5 and not just zipn?
Template Haskell can also be used to generate appropriate code for zipn (in fact, the original paper on TH even uses this as an example [1]). But again, this approach only works if the value of n is known at compile time. -Brent [1] http://www.haskell.org/th/papers/meta-haskell.ps

Frank Buss
Is it possible to write a function like this:
zipn n list_1 list_2 list_3 ... list_n
which implements zip3 for n=3, zip4 for n=4 etc.? Looks like variable number of arguments are possible, like printf shows, so a general zipn should be possible, too. If it is possible, why there are functions like zip5 and not just zipn?
Check out: Fridlender, Daniel, and Mia Indrika. 2000. Do we need dependent types? Journal of Functional Programming 10(4):409-415. http://www.math.chalmers.se/~indrika/jfp.ps.gz McBride, Conor. 2002. Faking it: Simulating dependent types in Haskell. Journal of Functional Programming 12(4-5): 375-392. -- Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig Remember Hirosima 1945-08-06, Nagasaki 1945-08-09. http://petitions.pm.gov.uk/Free-Vanunu/ http://www.vanunu.org/

On Sat, Aug 11, 2007 at 09:58:05AM +0200, Frank Buss wrote:
Is it possible to write a function like this:
zipn n list_1 list_2 list_3 ... list_n
which implements zip3 for n=3, zip4 for n=4 etc.? Looks like variable number of arguments are possible, like printf shows, so a general zipn should be possible, too. If it is possible, why there are functions like zip5 and not just zipn?
I prefer to do n-ary zips this way: zipApply = zipWith ($) x = repeat (,,) `zipApply` [1,2,3] `zipApply` ["a", "bc", "de"] `zipApply` [1.0, 1.2..] Best regards Tomek
participants (12)
-
Alexis Hazell
-
apfelmus
-
Brent Yorgey
-
Chung-chieh Shan
-
Conor McBride
-
Frank Buss
-
Hugh Perkins
-
Joel Koerwer
-
Marc Weber
-
Per Vognsen
-
Stefan O'Rear
-
Tomasz Zielonka