Related
Shouldn’t this definition be allowed in a lazy language like Haskell in which functions are curried?
apply f [] = f
apply f (x:xs) = apply (f x) xs
It’s basically a function that applies the given function to the given list of arguments and is very easily done in Lisp for example.
Are there any workarounds?
It is hard to give a static type to the apply function, since its type depends on the type of the (possibly heterogeneous) list argument. There are at least two ways one way to write this function in Haskell that I can think of:
Using reflection
We can defer type checking of the application until runtime:
import Data.Dynamic
import Data.Typeable
apply :: Dynamic -> [Dynamic] -> Dynamic
apply f [] = f
apply f (x:xs) = apply (f `dynApp` x) xs
Note that now the Haskell program may fail with a type error at runtime.
Via type class recursion
Using the semi-standard Text.Printf trick (invented by augustss, IIRC), a solution can be coded up in this style (exercise). It may not be very useful though, and still requires some trick to hide the types in the list.
Edit: I couldn't come up with a way to write this, without using dynamic types or hlists/existentials. Would love to see an example
I like Sjoerd Visscher's reply, but the extensions -- especially IncoherentInstances, used in this case to make partial application possible -- might be a bit daunting. Here's a solution that doesn't require any extensions.
First, we define a datatype of functions that know what to do with any number of arguments. You should read a here as being the "argument type", and b as being the "return type".
data ListF a b = Cons b (ListF a (a -> b))
Then we can write some (Haskell) functions that munge these (variadic) functions. I use the F suffix for any functions that happen to be in the Prelude.
headF :: ListF a b -> b
headF (Cons b _) = b
mapF :: (b -> c) -> ListF a b -> ListF a c
mapF f (Cons v fs) = Cons (f v) (mapF (f.) fs)
partialApply :: ListF a b -> [a] -> ListF a b
partialApply fs [] = fs
partialApply (Cons f fs) (x:xs) = partialApply (mapF ($x) fs) xs
apply :: ListF a b -> [a] -> b
apply f xs = headF (partialApply f xs)
For example, the sum function could be thought of as a variadic function:
sumF :: Num a => ListF a a
sumF = Cons 0 (mapF (+) sumF)
sumExample = apply sumF [3, 4, 5]
However, we also want to be able to deal with normal functions, which don't necessarily know what to do with any number of arguments. So, what to do? Well, like Lisp, we can throw an exception at runtime. Below, we'll use f as a simple example of a non-variadic function.
f True True True = 32
f True True False = 67
f _ _ _ = 9
tooMany = error "too many arguments"
tooFew = error "too few arguments"
lift0 v = Cons v tooMany
lift1 f = Cons tooFew (lift0 f)
lift2 f = Cons tooFew (lift1 f)
lift3 f = Cons tooFew (lift2 f)
fF1 = lift3 f
fExample1 = apply fF1 [True, True, True]
fExample2 = apply fF1 [True, False]
fExample3 = apply (partialApply fF1 [True, False]) [False]
Of course, if you don't like the boilerplate of defining lift0, lift1, lift2, lift3, etc. separately, then you need to enable some extensions. But you can get quite far without them!
Here is how you can generalize to a single lift function. First, we define some standard type-level numbers:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, TypeFamilies, UndecidableInstances #-}
data Z = Z
newtype S n = S n
Then introduce the typeclass for lifting. You should read the type I n a b as "n copies of a as arguments, then a return type of b".
class Lift n a b where
type I n a b :: *
lift :: n -> I n a b -> ListF a b
instance Lift Z a b where
type I Z a b = b
lift _ b = Cons b tooMany
instance (Lift n a (a -> b), I n a (a -> b) ~ (a -> I n a b)) => Lift (S n) a b where
type I (S n) a b = a -> I n a b
lift (S n) f = Cons tooFew (lift n f)
And here's the examples using f from before, rewritten using the generalized lift:
fF2 = lift (S (S (S Z))) f
fExample4 = apply fF2 [True, True, True]
fExample5 = apply fF2 [True, False]
fExample6 = apply (partialApply fF2 [True, False]) [False]
No, it cannot. f and f x are different types. Due to the statically typed nature of haskell, it can't take any function. It has to take a specific type of function.
Suppose f is passed in with type a -> b -> c. Then f x has type b -> c. But a -> b -> c must have the same type as a -> b. Hence a function of type a -> (b -> c) must be a function of type a -> b. So b must be the same as b -> c, which is an infinite type b -> b -> b -> ... -> c. It cannot exist. (continue to substitute b -> c for b)
Here's one way to do it in GHC. You'll need some type annotations here and there to convince GHC that it's all going to work out.
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE IncoherentInstances #-}
class Apply f a r | f -> a r where
apply :: f -> [a] -> r
instance Apply f a r => Apply (a -> f) a r where
apply f (a:as) = apply (f a) as
instance Apply r a r where
apply r _ = r
test = apply ((+) :: Int -> Int -> Int) [1::Int,2]
apply' :: (a -> a -> a) -> [a] -> a
apply' = apply
test' = apply' (+) [1,2]
This code is a good illustration of the differences between static and dynamic type-checking. With static type-checking, the compiler can't be sure that apply f really is being passed arguments that f expects, so it rejects the program. In lisp, the checking is done at runtime and the program might fail then.
I am not sure how much this would be helpful as I am writing this in F# but I think this can be easily done in Haskell too:
type 'a RecFunction = RecFunction of ('a -> 'a RecFunction)
let rec apply (f: 'a RecFunction) (lst: 'a list) =
match (lst,f) with
| ([],_) -> f
| ((x::xs), RecFunction z) -> apply (z x) xs
In this case the "f" in question is defined using a discriminated union which allows recursive data type definition. This can be used to solved the mentioned problem I guess.
With the help and input of some others I defined a way to achieve this (well, sort of, with a custom list type) which is a bit different from the previous answers. This is an old question, but it seems to still be visited so I will add the approach for completeness.
We use one extension (GADTs), with a list type a bit similar to Daniel Wagner's, but with a tagging function type rather than a Peano number. Let's go through the code in pieces. First we set the extension and define the list type. The datatype is polymorphic so in this formulation arguments don't have to have the same type.
{-# LANGUAGE GADTs #-}
-- n represents function type, o represents output type
data LApp n o where
-- no arguments applied (function and output type are the same)
End :: LApp o o
-- intentional similarity to ($)
(:$) :: a -> LApp m o -> LApp (a -> m) o
infixr 5 :$ -- same as :
Let's define a function that can take a list like this and apply it to a function. There is some type trickery here: the function has type n, a call to listApply will only compile if this type matches the n tag on our list type. By leaving our output type o unspecified, we leave some freedom in this (when creating the list we don't have to immediately entirely fix the kind of function it can be applied to).
-- the apply function
listApply :: n -> LApp n o -> o
listApply fun End = fun
listApply fun (p :$ l) = listApply (fun p) l
That's it! We can now apply functions to arguments stored in our list type. Expected more? :)
-- showing off the power of AppL
main = do print . listApply reverse $ "yrruC .B lleksaH" :$ End
print . listApply (*) $ 1/2 :$ pi :$ End
print . listApply ($) $ head :$ [1..] :$ End
print $ listApply True End
Unfortunately we are kind of locked in to our list type, we can't just convert normal lists to use them with listApply. I suspect this is a fundamental issue with the type checker (types end up depending on the value of a list) but to be honest I'm not entirely sure.
-- Can't do this :(
-- listApply (**) $ foldr (:$) End [2, 32]
If you feel uncomfortable about using a heterogeneous list, all you have to do is add an extra parameter to the LApp type, e.g:
-- Alternative definition
-- data FList n o a where
-- Nil :: FList o o a
-- Cons :: a -> FList f o a -> FList (a -> f) o a
Here a represents the argument type, where the function which is applied to will also have to accept arguments of all the same type.
This isn't precisely an answer to your original question, but I think it might be an answer to your use-case.
pure f <*> [arg] <*> [arg2] ...
-- example
λ>pure (\a b c -> (a*b)+c) <*> [2,4] <*> [3] <*> [1]
[7,13]
λ>pure (+) <*> [1] <*> [2]
[3]
The applicative instance of list is a lot broader than this super narrow use-case though...
λ>pure (+1) <*> [1..10]
[2,3,4,5,6,7,8,9,10,11]
-- Or, apply (+1) to items 1 through 10 and collect the results in a list
λ>pure (+) <*> [1..5] <*> [1..5]
[2,3,4,5,6,3,4,5,6,7,4,5,6,7,8,5,6,7,8,9,6,7,8,9,10]
{- The applicative instance of list gives you every possible combination of
elements from the lists provided, so that is every possible sum of pairs
between one and five -}
λ>pure (\a b c -> (a*b)+c) <*> [2,4] <*> [4,3] <*> [1]
[9,7,17,13]
{- that's - 2*4+1, 2*3+1, 4*4+1, 4*3+1
Or, I am repeating argC when I call this function twice, but a and b are
different -}
λ>pure (\a b c -> show (a*b) ++ c) <*> [1,2] <*> [3,4] <*> [" look mah, other types"]
["3 look mah, other types","4 look mah, other types","6 look mah, other types","8 look mah, other types"]
So it's not the same concept, precisely, but it a lot of those compositional use-cases, and adds a few more.
I find this documentation in the basic Haskell libraries:
zip :: [a] -> [b] -> [(a, b)]
zip takes two lists and returns a list of corresponding pairs. If one input list is short, excess elements of the longer list are discarded.
zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
zip3 takes three lists and returns a list of triples, analogous to zip.
zip4 :: [a] -> [b] -> [c] -> [d] -> [(a, b, c, d)]
The zip4 function takes four lists and returns a list of quadruples, analogous to zip.
[...snip...]
unzip :: [(a, b)] -> ([a], [b])
unzip transforms a list of pairs into a list of first components and a list of second components.
unzip3 :: [(a, b, c)] -> ([a], [b], [c])
The unzip3 function takes a list of triples and returns three lists, analogous to unzip.
unzip4 :: [(a, b, c, d)] -> ([a], [b], [c], [d])
The unzip4 function takes a list of quadruples and returns four lists, analogous to unzip.
... and so on, up to zip7 and unzip7.
Is this a fundamental limitation of Haskell's type system? Or is there a way to implement zip and unzip once, to work on different configurations of input?
This is one very useful aspect of applicatives. Check out ZipList which is just a newtype wrapper around a simple list. The reason for the wrapper is that ZipList has an applicative instance for, you guessed it, zipping lists together. Then, if you want zip7 as bs cs ds es fs gs hs, you can just do something like
(,,,,,,) <$> as <*> bs <*> cs <*> ds <*> es <*> fs <*> gs <*> hs
As you can tell, this mechanism is meant to be also for extending zipWith, which is a general case of zip. To be honest, I think we should rip out all of the zipN functions and teach people the above instead. zip itself is fine, but beyond that...
Template Haskell solution
As the comments and other answers indicate, this is not a particularly satisfying answer. The one thing I was expecting someone else to implement was a TemplateHaskell version of zip and unzip. As no one has done so yet, here it is.
All it does is mechanically produce AST for zip or unzip functions. The idea behind zip is to use ZipList and behind unzip is to use foldr:
zip as ... zs === \as ... zs -> getZipList $ (, ... ,) <$> ZipList as <*> ... <*> ZipList zs
unzip === foldr (\ (a, ... ,z) ~(as, ... ,zs) -> (a:as, ... ,z:zs) ) ([], ... ,[])
The implementation looks like this.
{-# LANGUAGE TemplateHaskell #-}
module Zip (zip, unzip) where
import Prelude hiding (zip, unzip)
import Language.Haskell.TH
import Control.Monad
import Control.Applicative (ZipList(..))
-- | Given number, produces the `zip` function of corresponding arity
zip :: Int -> Q Exp
zip n = do
lists <- replicateM n (newName "xs")
lamE (varP <$> lists)
[| getZipList $
$(foldl (\a b -> [| $a <*> ZipList $(varE b) |])
[| pure $(conE (tupleDataName n)) |]
lists) |]
-- | Given number, produces the `unzip` function of corresponding arity
unzip :: Int -> Q Exp
unzip n = do
heads <- replicateM n (newName "x")
tails <- replicateM n (newName "xs")
[| foldr (\ $(tupP (varP <$> heads)) ~ $(tupP (varP <$> tails)) ->
$(tupE (zipWith (\x xs -> [| $x : $xs |])
(varE <$> heads)
(varE <$> tails))))
$(tupE (replicate n [| [] |])) |]
You can try this at GHCi:
ghci> :set -XTemplateHaskell
ghci> $(zip 3) [1..10] "abcd" [4,6..]
[(1,'a',4),(2,'b',6),(3,'c',8),(4,'d',10)]
ghci> $(unzip 3) [(1,'a',4),(2,'b',6),(3,'c',8),(4,'d',10)]
([1,2,3,4],"abcd",[4,6,8,10])
This is a zipN function that depends on the machinery of the generics-sop package:
{-# language TypeFamilies #-}
{-# language DataKinds #-}
{-# language TypeApplications #-}
import Control.Applicative
import Generics.SOP
-- "a" is some single-constructor product type, like some form of n-ary tuple
-- "xs" is a type-level list of the types of the elements of "a"
zipN :: (Generic a, Code a ~ '[ xs ]) => NP [] xs -> [a]
zipN np = to . SOP . Z <$> getZipList (hsequence (hliftA ZipList np))
main :: IO ()
main = do
let zipped = zipN #(_,_,_) ([1,2,3,4,5,6] :* ['a','b','c'] :* [True,False] :* Nil)
print $ zipped
The result:
[(1,'a',True),(2,'b',False)]
This solution has two disadvantages:
You have to wrap the argument lists in the special NP type from generics-sop that is constructed with :* and Nil.
You need to specify somehow that the result value is a list of tuples, and not a list of some other Generic-compatible type. Here, it is done with the #(_,_,_) type application.
2-ary, 3-ary.. n-ary tuples are all distinct data types, so you can't handle them uniformly directly, but you can introduce a type class that provides an interface that allows to define generic zip and unzip. Here is how it looks for generic unzip:
class Tuple t where
type Map (f :: * -> *) t
nilMap :: Proxy t -> (forall a. f a) -> Map f t
consMap :: (forall a. a -> f a -> f a) -> t -> Map f t -> Map f t
Map maps all types in a tuple type with f. nilMap constructs a Mapped tuple that contains empty values (I have no idea why Haskell requires that Proxy t there). consMap receives a function, a tuple and a Mapped tuple and zip the tuples with the function pointwise. Here is how instances look for 2- and 3-tuples:
instance Tuple (a, b) where
type Map f (a, b) = (f a, f b)
nilMap _ a = (a, a)
consMap f (x, y) (a, b) = (f x a, f y b)
instance Tuple (a, b, c) where
type Map f (a, b, c) = (f a, f b, f c)
nilMap _ a = (a, a, a)
consMap f (x, y, z) (a, b, c) = (f x a, f y b, f z c)
The gunzip itself:
gunzip :: forall t. Tuple t => [t] -> Map [] t
gunzip [] = nilMap (Proxy :: Proxy t) []
gunzip (p:ps) = consMap (:) p (gunzip ps)
This looks a lot like transpose:
transpose :: [[a]] -> [[a]]
transpose [] = repeat [] -- `gunzip` handles this case better
transpose (xs:xss) = zipWith (:) xs (transpose xss)
which it basically is, except with tuples. gunzip can be equivalently defined in terms of foldr as follows:
gunzip :: forall t. Tuple t => [t] -> Map [] t
gunzip = foldr (consMap (:)) $ nilMap (Proxy :: Proxy t) []
To define generic zip we need a type class of splittable data types (is there something like this on Hackage?).
class Splittable f g where
split :: f a -> g a (f a)
E.g. for lists we have
newtype MaybeBoth a b = MaybeBoth { getMaybeBoth :: Maybe (a, b) }
instance Splittable [] MaybeBoth where
split [] = MaybeBoth Nothing
split (x:xs) = MaybeBoth (Just (x, xs))
And here is what we add to the Tuple type class:
splitMap :: (Biapplicative g, Splittable f g) => Proxy (f t) -> Map f t -> g t (Map f t)
The Biapplicative g constraint ensures that it's possible to combine g a b and g c d into g (a, c) (b, d). For 2- and 3- tuples it looks like this:
splitMap _ (a, b) = biliftA2 (,) (,) (split a) (split b)
splitMap _ (a, b, c) = biliftA3 (,,) (,,) (split a) (split b) (split c)
After providing a Biapplicative instance for MaybeBoth
instance Biapplicative MaybeBoth where
bipure x y = MaybeBoth $ Just (x, y)
MaybeBoth f <<*>> MaybeBoth a = MaybeBoth $ uncurry (***) <$> f <*> a
we can finally define gzip:
gzip :: forall t. Tuple t => Map [] t -> [t]
gzip a = maybe [] (\(p, a') -> p : gzip a') . getMaybeBoth $ splitMap (Proxy :: Proxy [t]) a
It repeteadly cuts first elements of lists in a tuple, forms a tuple from them and prepends it to the result.
It should be possible to generalize gunzip by adding a dual to Splittable (Uniteable or something like that), but I'll stop here.
EDIT: I couldn't stop.
You are right that these functions (zip2, zip3 etc.) are all instances of the same pattern and in an ideal world, they should be implementable generically. By the way, as an exercise to the reader, figure out what zip1 and zip0 should be ;).
However, it is hard to implement zipN generically, because the common pattern between all the different cases is rather non-trivial. This does not mean it's impossible to implement it generically, but you'll need some of the more advanced type system features of Haskell GHC to do it.
To be more concrete, zip2, zip3 etc. all have a different number of arguments, making this an instance of "arity-generic programming" (the arity of a function is its number of arguments). As you might expect in the world of functional programming, there is an interesting research paper that covers precisely this topic ("arity-generic programming"), and conveniently, one of their main examples is... zipWithN. It doesn't directly answer your question because it uses Agda rather than Haskell, but you might still find it interesting. In any case, similar ideas can be implemented in terms of one or more of Haskell's GHC's more advanced type-system features (TypeFamilies and DataKinds come to mind). PDF version here.
By the way, this is just about an arity-generic zipWithN. For an arity-generic zipN, you probably need some support from the compiler, particularly an arity-generic interface to the tuple constructor, which I suspect might not be in GHC. This is what I believe augustss's comment to the question and chepner's comment to Alec's answer refer to.
I want to build a list of different things which have one property in common, namely, they could be turned into string. The object-oriented approach is straightforward: define interface Showable and make classes of interest implement it. Second point can in principle be a problem when you can't alter the classes, but let's pretend this is not the case. Then you create a list of Showables and fill it with objects of these classes without any additional noise (e.g. upcasting is usually done implicitly). Proof of concept in Java is given here.
My question is what options for this do I have in Haskell? Below I discuss approaches that I've tried and which don't really satisfy me.
Approach 1: existensials. Works but ugly.
{-# LANGUAGE ExistentialQuantification #-}
data Showable = forall a. Show a => Sh a
aList :: [Showable]
aList = [Sh (1 :: Int), Sh "abc"]
The main drawback for me here is the necessity for Sh when filling the list. This closely resembles upcast operations which are implicitly done in OO-languages.
More generally, the dummy wrapper Showable for the thing which is already in the language — Show type class — adds extra noise in my code. No good.
Approach 2: impredicatives. Desired but does not work.
The most straightforward type for such a list for me and what I really desire would be:
{-# LANGUAGE ImpredicativeTypes #-}
aList :: [forall a. Show a => a]
aList = [(1 :: Int), "abc"]
Besides that (as I heard)ImpredicativeTypes is “fragile at best and broken at worst”
it does not compile:
Couldn't match expected type ‘a’ with actual type ‘Int’
‘a’ is a rigid type variable bound by
a type expected by the context: Show a => a
and the same error for "abc". (Note type signature for 1: without it I receive even more weird message: Could not deduce (Num a) arising from the literal ‘1’).
Approach 3: Rank-N types together with some sort of functional lists (difference lists?).
Instead of problematic ImpredicativeTypes one would probably prefer more stable and wide-accepted RankNTypes. This basically means: move
desired forall a. Show a => a out of type constructor (i.e. []) to plain function types. Consequently we need some representation of lists as plain functions. As I barely heard there are such representations. The one I heard of is difference lists. But in Dlist package the main type is good old data so we return to impredicatives. I didn't investigate this line any further as I suspect that it could yield more verbose code than in approach 1. But if you think it won't, please give me an example.
Bottom line: how would you attack such a task in Haskell? Could you give more succinct solution than in OO-language (especially in place of filling a list — see comment for code in approach 1)? Can you comment on how relevant are the approaches listed above?
UPD (based on first comments): the question is of course simplified for the purpose of readability. The real problem is more about how to store things which share the same type class, i.e. can be processed later on in a number of ways (Show has only one method, but other classes can have more than one). This factors out solutions which suggest apply show method right when filling a list.
Since evaluation is lazy in Haskell, how about just creating a list of the actual strings?
showables = [ show 1, show "blah", show 3.14 ]
The HList-style solutions would work, but it is possible to reduce the complexity if you only need to work with lists of constrained existentials and you don't need the other HList machinery.
Here's how I handle this in my existentialist package:
{-# LANGUAGE ConstraintKinds, ExistentialQuantification, RankNTypes #-}
data ConstrList c = forall a. c a => a :> ConstrList c
| Nil
infixr :>
constrMap :: (forall a. c a => a -> b) -> ConstrList c -> [b]
constrMap f (x :> xs) = f x : constrMap f xs
constrMap f Nil = []
This can then be used like this:
example :: [String]
example
= constrMap show
(( 'a'
:> True
:> ()
:> Nil) :: ConstrList Show)
It could be useful if you have a large list or possibly if you have to do lots of manipulations to a list of constrained existentials.
Using this approach, you also don't need to encode the length of the list in the type (or the original types of the elements). This could be a good thing or a bad thing depending on the situation. If you want to preserve the all of original type information, an HList is probably the way to go.
Also, if (as is the case of Show) there is only one class method, the approach I would recommend would be applying that method to each item in the list directly as in ErikR's answer or the first technique in phadej's answer.
It sounds like the actual problem is more complex than just a list of Show-able values, so it is hard to give a definite recommendation of which of these specifically is the most appropriate without more concrete information.
One of these methods would probably work out well though (unless the architecture of the code itself could be simplified so that it doesn't run into the problem in the first place).
Generalizing to existentials contained in higher-kinded types
This can be generalized to higher kinds like this:
data AnyList c f = forall a. c a => f a :| (AnyList c f)
| Nil
infixr :|
anyMap :: (forall a. c a => f a -> b) -> AnyList c f -> [b]
anyMap g (x :| xs) = g x : anyMap g xs
anyMap g Nil = []
Using this, we can (for example) create a list of functions that have Show-able result types.
example2 :: Int -> [String]
example2 x = anyMap (\m -> show (m x))
(( f
:| g
:| h
:| Nil) :: AnyList Show ((->) Int))
where
f :: Int -> String
f = show
g :: Int -> Bool
g = (< 3)
h :: Int -> ()
h _ = ()
We can see that this is a true generalization by defining:
type ConstrList c = AnyList c Identity
(>:) :: forall c a. c a => a -> AnyList c Identity -> AnyList c Identity
x >: xs = Identity x :| xs
infixr >:
constrMap :: (forall a. c a => a -> b) -> AnyList c Identity -> [b]
constrMap f (Identity x :| xs) = f x : constrMap f xs
constrMap f Nil = []
This allows the original example from the first part of this to work using this new, more general, formulation with no changes to the existing example code except changing :> to >: (even this small change might be able to be avoided with pattern synonyms. I'm not totally sure though since I haven't tried and sometimes pattern synonyms interact with existential quantification in ways that I don't fully understand).
If you really, really want, you can use a heterogeneous list. This approach really isn't useful for Show, because it has a single method and all you can do is apply it, but if your class has multiple methods this could be useful.
{-# LANGUAGE PolyKinds, KindSignatures, GADTs, TypeFamilies
, TypeOperators, DataKinds, ConstraintKinds, RankNTypes, PatternSynonyms #-}
import Data.List (intercalate)
import GHC.Prim (Constraint)
infixr 5 :&
data HList xs where
None :: HList '[]
(:&) :: a -> HList bs -> HList (a ': bs)
-- | Constraint All c xs holds if c holds for all x in xs
type family All (c :: k -> Constraint) xs :: Constraint where
All c '[] = ()
All c (x ': xs) = (c x, All c xs)
-- | The list whose element types are unknown, but known to satisfy
-- a class predicate.
data CList c where CL :: All c xs => HList xs -> CList c
cons :: c a => a -> CList c -> CList c
cons a (CL xs) = CL (a :& xs)
empty :: CList c
empty = CL None
uncons :: (forall a . c a => a -> CList c -> r) -> r -> CList c -> r
uncons _ n (CL None) = n
uncons c n (CL (x :& xs)) = c x (CL xs)
foldrC :: (forall a . c a => a -> r -> r) -> r -> CList c -> r
foldrC f z = go where go = uncons (\x -> f x . go) z
showAll :: CList Show -> String
showAll l = "[" ++ intercalate "," (foldrC (\x xs -> show x : xs) [] l) ++ "]"
test = putStrLn $ showAll $ CL $
1 :&
'a' :&
"foo" :&
[2.3, 2.5 .. 3] :&
None
You can create your own operator to reduce syntax noise:
infixr 5 <:
(<:) :: Show a => a -> [String] -> [String]
x <: l = show x : l
So you can do:
λ > (1 :: Int) <: True <: "abs" <: []
["1","True","\"abs\""]
This is not [1 :: Int, True, "abs"] but not much longer.
Unfortunately you cannot rebind [...] syntax with RebindableSyntax.
Another approach is to use HList and preserve all type information, i.e. no downcasts, no upcasts:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
import GHC.Exts (Constraint)
infixr 5 :::
type family All (c :: k -> Constraint) (xs :: [k]) :: Constraint where
All c '[] = ()
All c (x ': xs) = (c x, All c xs)
data HList as where
HNil :: HList '[]
(:::) :: a -> HList as -> HList (a ': as)
instance All Show as => Show (HList as) where
showsPrec d HNil = showString "HNil"
showsPrec d (x ::: xs) = showParen (d > 5) (showsPrec 5 x)
. showString " ::: "
. showParen (d > 5) (showsPrec 5 xs)
And after all that:
λ *Main > (1 :: Int) ::: True ::: "foo" ::: HNil
1 ::: True ::: "foo" ::: HNil
λ *Main > :t (1 :: Int) ::: True ::: "foo" ::: HNil
(1 :: Int) ::: True ::: "foo" ::: HNil
:: HList '[Int, Bool, [Char]]
There are various ways to encode heterogenous list, in HList is one, there is also generics-sop with NP I xs. It depends on what you are trying to achieve in the larger context, if this is this preserve-all-the-types approach is what you need.
I would do something like this:
newtype Strings = Strings { getStrings :: [String] }
newtype DiffList a = DiffList { getDiffList :: [a] -> [a] }
instance Monoid (DiffList a) where
mempty = DiffList id
DiffList f `mappend` DiffList g = DiffList (f . g)
class ShowList a where
showList' :: DiffList String -> a
instance ShowList Strings where
showList' (DiffList xs) = Strings (xs [])
instance (Show a, ShowList b) => ShowList (a -> b) where
showList' xs x = showList' $ xs `mappend` DiffList (show x :)
showList = showList' mempty
Now, you can create a ShowList as follows:
myShowList = showList 1 "blah" 3.14
You can get back a list of strings using getStrings as follows:
myStrings = getStrings myShowList
Here's what's happening:
A value of the type ShowList a => a could be:
Either a list of strings wrapped in a Strings newtype wrapper.
Or a function from an instance of Show to an instance of ShowList.
This means that the function showList is a variadic argument function which takes an arbitrary number of printable values and eventually returns a list of strings wrapped in a Strings newtype wrapper.
You can eventually call getStrings on a value of the type ShowList a => a to get the final result. In addition, you don't need to do any explicit type coercion yourself.
Advantages:
You can add new elements to your list whenever you want.
The syntax is succinct. You don't have to manually add show in front of every element.
It doesn't make use of any language extensions. Hence, it works in Haskell 98 too.
You get the best of both worlds, type safety and a great syntax.
Using difference lists, you can construct the result in linear time.
For more information on functions with variadic arguments, read the answer to the following question:
How does Haskell printf work?
My answer is fundamentally the same as ErikR's: the type that best embodies your requirements is [String]. But I'll go a bit more into the logic that I believe justifies this answer. The key is in this quote from the question:
[...] things which have one property in common, namely, they could be turned into string.
Let's call this type Stringable. But now the key observation is this:
Stringable is isomorphic to String!
That is, if your statement above is the whole specification of the Stringable type, then there is a pair functions with these signatures:
toString :: Stringable -> String
toStringable :: String -> Stringable
...such that the two functions are inverses. When two types are isomorphic, any program that uses either of the types can be rewritten in terms of the other without any change to its semantics. So Stringable doesn't let you do anything that String doesn't let you do already!
In more concrete terms, the point is that this refactoring is guaranteed to work no matter what:
At every point in your program where you turn an object into a Stringable and stick that into a [Stringable], turn the object into a String and stick that into a [String].
At every point in your program that you consume a Stringable by applying toString to it, you can now eliminate the call to toString.
Note that this argument generalizes to types more complex than Stringable, with many "methods". So for example, the type of "things that you can turn into either a String or an Int" is isomorphic to (String, Int). The type of "things that you can either turn into a String or combine them with a Foo to produce a Bar" is isomorphic to (String, Foo -> Bar). And so on. Basically, this logic leads to the "record of methods" encoding that other answers have brought up.
I think the lesson to draw from this is the following: you need a specification richer than just "can be turned into a string" in order to justify using any of the mechanisms you brought up. So for example, if we add the requirement that Stringable values can be downcast to the original type, an existential type now perhaps becomes justifiable:
{-# LANGUAGE GADTs #-}
import Data.Typeable
data Showable = Showable
Showable :: (Show a, Typeable a) => a -> Stringable
downcast :: Typeable a => Showable -> Maybe a
downcast (Showable a) = cast a
This Showable type is not isomorphic to String, because the Typeable constraint allows us to implement the downcast function that allows us to distinguish between different Showables that produce the same string. A richer version of this idea can be seen in this "shape example" Gist.
You can store partially applied functions in the list.
Suppose we are building a ray-tracer with different shape that you can intersect.
data Sphere = ...
data Triangle = ...
data Ray = ...
data IntersectionResult = ...
class Intersect t where
intersect :: t -> Ray -> Maybe IntersectionResult
instance Intersect Sphere where ...
instance Intersect Triangle where ...
Now, we can partially apply the intersect to get a list of Ray -> Maybe IntersectionResult such as:
myList :: [(Ray -> Maybe IntersectionResult)]
myList = [intersect sphere, intersect triangle, ...]
Now, if you want to get all the intersections, you can write:
map ($ ray) myList -- or map (\f -> f ray) myList
This can be extended a bit to handle an interface with multiples functions, for example, if you want to be able to get something of a shape :
class ShapeWithSomething t where
getSomething :: t -> OtherParam -> Float
data ShapeIntersectAndSomething = ShapeIntersectAndSomething {
intersect :: Ray -> Maybe IntersectionResult,
getSomething :: OtherParam -> Float}
Something I don't know is the overhead of this approach. We need to store the pointer to the function and the pointer to the shape and this for each function of the interface, which is a lot compared to the shared vtable usually used in OO language. I don't have any idea if GHC is able to optimize this.
The core of the problem is : you want to dispatch (read select which function to call) at runtime, depending on what the "type" of the object is. In Haskell this can be achieved by wrapping the data into a sum data type (which is called here ShowableInterface):
data ShowableInterface = ShowInt Int | ShowApple Apple | ShowBusiness Business
instance Show ShowableInterface where
show (ShowInt i) = show i
show (ShowApple a) = show a
show (ShowBusiness b) = show b
list=[ShowInt 2, ShowApple CrunchyGold, ShowBusiness MoulinRouge]
show list
would correspond to something like this in Java :
class Int implements ShowableInterface
{
public show {return Integer.asString(i)};
}
class Apple implements ShowableInterface
{
public show {return this.name};
}
class ShowBusiness implements ShowableInterface
{
public show {return this.fancyName};
}
List list = new ArrayList (new Apple("CrunchyGold"),
new ShowBusiness("MoulingRouge"), new Integer(2));
so in Haskell you need to explicitly wrap stuff into the ShowableInterface, in Java this wrapping is done implicitly on object creation.
credit goes to #haskell IRC for explaining this to me a year ago, or so.
I am trying to combine an arbitrary number of mathematical functions that are in a list.
I've written a compose function that chains them together:
chain :: (c -> d) -> (a -> b -> c) -> a -> b -> d
g `chain` f = \a b -> g (f a b)
So doing something like
let b = (*) `chain` (+) `chain` (-)
Creates a function that takes a b c d, and does ((a − b) + c) × d
> b 2 3 4 5
> 15
My question is, I want to be able to chain a set of these together based on an arbitrary list:
[(*),(+),(-)] would result in (*) `chain` (+) `chain` (-)
[(*),(+),(-),(*)] would result in (*) `chain` (+) `chain` (-) `chain` (*)
Is this possible? I've tried using folds but cannot get it to work since the type of the accumulator changes after each application of an element.
For example, the type of three functions chained together is:
b :: Integer -> Integer -> Integer -> Integer -> Integer
But for four it is:
b :: Integer -> Integer -> Integer -> Integer -> Integer -> Integer
If someone could point me in the right direction or knows of a solution, that would be great! Thank you.
EDIT:
My end goal is to be able to do something like this:
getZipList $ pure (function composing * and +) <*> ZipList [1,2,3] <*> ZipList [4,5,6]
<*> ZipList [7,8,9]
would result in:
[(1+4)*7, (2+5)*8, (3+6)*9]
Well, as you note yourself it can't really be possible, since different lists lengths (invisible to the type system) would result in different types. The only "solid" way do do it would be some kind of compile-time list; there are various around but none of them is really stably supported and easy to use.
The easiest alternative would be to also take the arguments as a list. i.e.,
ifxChain :: [a->a->a] -> [a] -> a
That one could easily be implemented: it's basically a zip to supply the second argument to each function, ommiting the first one. Then you fold that first parameter through the resulting list of single-parameter functions:
ifxChain fs (p0:ps) = foldl' (flip ($)) p0 $ zipWith flip fs ps
You may want to add handling of lists with non-matching lengths, should be doable reasonably safe.
If you insist on an actual variable number of function arguments (I don't think this is good!) then you need quite some type-class hackery. Such variadic functions are best known from printf.
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
class ChainedFunc f t where
chainIfxs :: [t->t->t] -> t -> f
chainIfxs fs i = chainIfxPre i id $ reverse fs
chainIfxPre :: t -> (t->t) -> [t->t->t] -> f
instance ChainedFunc t t where
chainIfxPre i f [] = f i
instance (ChainedFunc f t) => ChainedFunc (t->f) t where
chainIfxPre i fin (f:fs) x0 = chainIfxPre i (flip f x0 . fin) fs
Obviously, this is in many ways not nice at all. But, well, it works... ahm...
Main> chainIfxs [(*),(+),(-)] (2 :: Int) (3 :: Int) (4 :: Int) (5 :: Int) :: Int
15
Could this idea help you develop a general function?
Prelude> :m +Data.List
Prelude Data.List> let fs = [(-),(+),(*)]
Prelude Data.List> foldl' (\accum (i,f) -> accum `f` i) 2 (zip [3..5] fs)
15
I'm not a Haskell programmer, but I'm curious about the following questions.
Informal function specification:
Let MapProduct be a function that takes a function called F and multiple lists. It returns a list containing the results of calling F with one argument from each list in each possible combination.
Example:
Call MapProduct with F being a function that simply returns a list of its arguments, and two lists. One of the lists contains the integers 1 and 2, the other one contains the strings "a" and "b". It should return a list that contains the lists: 1 and "a", 1 and "b", 2 and "a", 2 and "b".
Questions:
How is MapProduct implemented?
What is the function's type? What is F's type?
Can one guess what the function does just by looking at its type?
Can you handle inhomogeneous lists as input? (e.g. 1 and "a" in one of the input lists)
What extra limitation (if any) do you need to introduce to implement MapProduct?
How is MapProduct implemented?
.
Prelude> :m + Control.Applicative
Prelude Control.Applicative> (,,) <$> [1,2,3] <*> ["a","b","c"] <*> [0.8, 1.2, 4.4]
[(1,"a",0.8),(1,"a",1.2),...,(3,"c",4.4)]
What is the function's type? What is F's type?
The type of F depends on the list you want to apply. <$> here is fmap, and (<*>) :: f(a->b) -> f a -> f b where f = [] here.
Can you handle inhomogeneous lists as input? (e.g. 1 and "a" in one of the input lists)
There is no such thing as an heterogeneous list. But you can simulate a heterogeneous list for a specific context with existential types. And then you can just use the method above to do the MapProduct.
*Main Control.Applicative> :i SB
data ShowBox where
SB :: forall s. (Show s) => s -> ShowBox
-- Defined at v.hs:1:35-36
*Main Control.Applicative> [SB 2, SB "a", SB 6.4]
[2,"a",6.4]
*Main Control.Applicative> (,) <$> [SB 2, SB "a", SB 6.4] <*> [SB 'z', SB 44]
[(2,'z'),(2,44),("a",'z'),("a",44),(6.4,'z'),(6.4,44)]
It is possible to define a function mapProduct that works for any arity of function:
{-# LANGUAGE FlexibleInstances, TypeFamilies #-}
module MapProduct (
mapProduct
) where
import Control.Monad
newtype ProdFuncList a b = ProdFuncList [ a -> b ]
class MapProdResult p where
type MapProdArg p
apNext :: ProdFuncList x (MapProdArg p) -> [x] -> p
instance (MapProdResult b) => MapProdResult ([a] -> b) where
type MapProdArg ([a] -> b) = (a -> MapProdArg b)
apNext (ProdFuncList fs) = apNext . ProdFuncList . ap fs
instance MapProdResult [b] where
type MapProdArg [b] = b
apNext (ProdFuncList fs) = ap fs
mapProduct :: (MapProdResult q) => (a -> MapProdArg q) -> [a] -> q
mapProduct f = apNext (ProdFuncList [f])
Here it is in action:
> :l MapProduct.hs
[1 of 1] Compiling MapProduct ( MapProduct.hs, interpreted )
Ok, modules loaded: MapProduct.
> mapProduct (+10) [1..4] :: [Int]
[11,12,13,14]
> mapProduct (*) [1..4] [10..12] :: [Int]
[10,11,12,20,22,24,30,33,36,40,44,48]
> mapProduct (\a b c -> a:b:c:[]) "bcs" "ao" "dnt" :: [String]
["bad","ban","bat","bod","bon","bot","cad","can","cat","cod","con","cot","sad","san","sat","sod","son","sot"]
The downside of this approach is that you'll most likely have to type annotate the result (as shown in the examples above). It would be much more idiomatic to simply use fmap and ap directly:
> :m + Control.Monad
> (+10) `fmap` [1..4]
[11,12,13,14]
> (*) `fmap` [1..4] `ap` [10..12]
[10,11,12,20,22,24,30,33,36,40,44,48]
> (\a b c -> a:b:c:[]) `fmap` "bcs" `ap` "ao" `ap` "dnt"
["bad","ban","bat","bod","bon","bot","cad","can","cat","cod","con","cot","sad","san","sat","sod","son","sot"]
This requires no type annotations, and is fully general over all monads, not just [].
(The MapProduct module above could easily be generalized over all monads as well. I didn't so as to make it clearly solve the original question.)
The function that you describe is closely related to the zipWithN functions. It will have the same type - it will just result in bigger result lists. Now the problem is that there is no way to express "a function that takes N arguments of the types t_1, ..., t_n" or "n lists of the types [t_1],...,[t_n]" (or "an n-tuple of type ([t_1], ..., [t_n]") ) in haskell's type system (without extensions like template haskell). This is why there is not one zipWith function, but one for each number of arguments lists that is supported.
So to answer your questions:
It is implemented by defining a function mapProductN for every number N that you want to support. For N=2 it would look like this:
mapProduct f l1 l2 = [f x1 x2 | x1 <- l1, x2 <- x2]
Or as a general blueprint (i.e. pseudo-code) how to define the functions for any N:
mapProduct f l1 ... ln = [f x1 ... xn | x1 <- l1, ..., xn <- ln]
As I said it's the same as the types of the zipWith functions, i.e.:
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
zipWith4 :: (a -> b -> c -> d -> e) -> [a] -> [b] -> [c] -> [d] -> [e]
Since f is the first argument to the function, the type of the first argument is f's type (so for n=2 it'd be a -> b -> c)
Well since it has the same type as zipWith and zipWith does something else, that'd be a no.
Haskell doesn't allow inhomogeneous lists without an extension.
There's an upper limit on the number of lists unless you're willing to spend the time writing infinite versions of mapProduct.