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 asked a similar question before (how to implement mapAccumM?).
I need the one which folds from the right as well (mapAccumR):
mapAccumRM :: (Monad m, Traversable t)
=> (a -> b -> m (a, c)) -> a -> t b -> m (a, t c)
Is there a simple implementation for this?
One approach is to define new instances of Traversable that use the ordering you like. For example, for lists, one might simply define a new type:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Control.Applicative
import Data.Traversable
newtype BackwardsList a = BackwardsList [a]
deriving (Eq, Ord, Read, Show, Functor, Foldable)
instance Traversable BackwardsList where
traverse f (BackwardsList xs) = BackwardsList <$> go xs where
go [] = pure []
go (x:xs) = liftA2 (flip (:)) (go xs) (f x)
In ghci, we can see the difference between this and the standard instance:
> runState (traverse (\_ -> modify (+1) >> get) "hello, world!") 0
([1,2,3,4,5,6,7,8,9,10,11,12,13],13)
> runState (traverse (\_ -> modify (+1) >> get) (BackwardsList "hello, world!")) 0
(BackwardsList [13,12,11,10,9,8,7,6,5,4,3,2,1],13)
This approach is fairly simple; however, it requires a new type (and the associated newtype wrapping/unwrapping garbage) for every new traversal order that you are interested in.
One could consider defining a new type class for ordered traversals. Let's see one way this might be done. We'll need a little prelude:
{-# LANGUAGE Rank2Types, TypeFamilies #-}
import Control.Applicative
import Data.Foldable
import Data.Traversable
import Data.Tree
Most Haskell data types can be viewed as fixed-points of polynomial functors; and the functors that they are fixed-points of are good descriptions of the "spine" of the data structure. We'll abuse this idea to give a concrete way to encode the ordering that should be used during traversal. The class itself looks like this:
type Order t = forall f a. Applicative f => Spine t (f a) (f (t a)) -> f (t a)
class OrderedTraversable t where
data Spine t :: * -> * -> *
otraverse :: Applicative f => Order t -> (a -> f b) -> t a -> f (t b)
Notice that the type of otraverse looks just like the type of traverse, except that it now takes an extra ordering argument. The ordering argument is, in a sense, variadic; since different data types have different numbers of values/children at various places in their structure, and the ordering may care about all of them. (Of special interest is here is the technique of using rank-2 types to prevent an ordering from observing "too much" about a data structure: it can't use special facts about a given instance of Applicative or given kind of element to decide how to traverse a spine, only decisions based on the shape of the spine are allowed.) Let's see a simple example, for lists:
instance OrderedTraversable [] where
-- Cute hack: the normal presentation for the spine of a list uses both
-- a `Cons` and a `Nil`; but parametricity says the only thing an
-- `Order []` can do with a `Nil` is `pure []` anyway. So let's just
-- bake that into `otraverse`.
data Spine [] a r = Cons a r
otraverse order f = go where
go [] = pure []
go (x:xs) = order (Cons (f x) (go xs))
Compare with the implementation of Traversable for lists in the standard library (I have taken the liberty of expanding the definition of foldr to make it more closely match the code above):
instance Traversable [] where
traverse f = go where
go [] = pure []
go (x:xs) = (:) <$> f x <*> go xs
As you can see, the primary difference is that we have abstracted which function to use to combine f x and go xs. We can recover the standard Traversable instance with a "head-first" order. There is also a "last-first" order; and these are basically the only two orders that make sense for lists.
headFirst, lastFirst :: Order []
headFirst (Cons fx fxs) = liftA2 (:) fx fxs
lastFirst (Cons fx fxs) = liftA2 (flip (:)) fxs fx
In ghci, we can now see how they differ:
> runState (traverse (\_ -> modify (+1) >> get) "hello, world!") 0
([1,2,3,4,5,6,7,8,9,10,11,12,13],13)
> runState (otraverse headFirst (\_ -> modify (+1) >> get) "hello, world!") 0
([1,2,3,4,5,6,7,8,9,10,11,12,13],13)
> runState (otraverse lastFirst (\_ -> modify (+1) >> get) "hello, world!") 0
([13,12,11,10,9,8,7,6,5,4,3,2,1],13)
To give another example, here is how you might use this class with rose trees:
instance OrderedTraversable Tree where
data Spine Tree a r = SNode a [r]
otraverse order f = go where
go (Node x ts) = order (SNode (f x) (map go ts))
-- two example orders for trees
prefix, postfix :: Order [] -> Order Tree
prefix list (SNode fx fts) = liftA2 Node fx (otraverse list id fts)
postfix list (SNode fx fts) = liftA2 (flip Node) (otraverse list id fts) fx
Note that there are actually infinitely many "good" ordering functions for rose trees; two that are particularly likely to be what you want are included above.
First of all let me apologize, yet I simply couldn't find the answer to my
question although I'm pretty sure that this has been asked before. Now:
I would like to write Functor and Monad instances for a binary (search)
tree. More precisely, some of the functions like insert or merge require
instances of Ord, e.g.:
data Tree a = Empty | Node a (Tree a) (Tree a)
insert :: (Ord a) => Tree a -> a -> Tree a
merge :: (Ord a) => Tree a -> Tree a -> Tree a
Consequently, the following code doesn't compile:
instance Monad Tree where
{- ... -}
Empty >>= f = Empty
(Node v l r) >>= f = merge (f v) (merge newL newR)
where newL = l >>= f
newR = r >>= f
-- No instance for (Ord b) arising from a use of `merge'...
As I didn't know any better, I've tried declaring the Ord constraint on the
ADT using DatatypeContexts but that's deprecated and didn't work anyway. Other
extensions like FlexibleInstances etc. all seemed useful until I realized they
really meant something else.
So, is there a way and how would I go about it? Thank you for your time.
EDIT: Meanwhile I found this useful answer, but it appears as if doing this kind of stuff for typeclasses like Functor is still an issue.
There are various ways you can do this, but none of them are completely clean.
The key term you should look up is "restricted monad".
Here's one example with the rmonad package (which I wrote).
{-# LANGUAGE NoImplicitPrelude, TypeFamilies, GADTs,
FlexibleInstances, MultiParamTypeClasses #-}
import Control.RMonad.Prelude
import Data.Suitable
data Tree a = Empty | Node a (Tree a) (Tree a)
insert :: (Ord a) => Tree a -> a -> Tree a
insert = undefined
merge :: (Ord a) => Tree a -> Tree a -> Tree a
merge = undefined
data instance Constraints Tree a where
TreeConstraints :: Ord a => Constraints Tree a
instance Ord a => Suitable Tree a where
constraints = TreeConstraints
instance RFunctor Tree where
fmap f Empty = Empty
fmap f (Node v l r) = Node (f v) (fmap f l) (fmap f r)
instance RMonad Tree where
{- ... -}
Empty >>= f = Empty
(Node v l r) >>= f = withResConstraints $ \TreeConstraints ->
merge (f v) (merge newL newR)
where newL = l >>= f
newR = r >>= f
See the general documentation for the package here.
Note that RMonad is a different type class to Monad. If you want to have a real Monad instance you can use AsMonad Tree.
(Apology by the title, I can't do better)
My question is to find some generalized struct or "standard" function to perform the next thing:
xmap :: (a -> b) -> f a -> g b
then, we can map not only elements, by also the entire struct.
Some (not real) example
xmap id myBinaryTree :: [a]
at the moment, I must to do a explicit structure conversor (typical fromList, toList) then
toList . fmap id -- if source struct has map
fmap id . fromList -- if destination struct has map
(to perform toStruct, fromStruct I use fold).
Exists some way to generalize to/from structs? (should be)
Exists that function (xmap)?
Thank you!! :)
As f and g are functors, a natural transformation is what you're looking for (see also You Could Have Defined Natural Transformations). So a transformation like
f :~> g = forall a. f a -> g a
is needed to create xmap which is then just
xmap :: (a -> b) -> (f :~> g) -> (f a -> g b)
xmap f n = map f . n
You still need to define types of (f :~> g), but there' not a general way of doing that.
I'd like to add to tel's answer (I got my idea only after reading it) that in many cases you can make general natural transformation that will work similarly to foldMap. If we can use foldMap, we know that f is Foldable. Then we need some way how to constructs elements of g a and combine them together. We can use Alternative for that, it has all we need (pure, empty and <|>), although we could also construct some less general type class for this purpose (we don't need <*> anywhere).
{-# LANGUAGE TypeOperators, RankNTypes #-}
import Prelude hiding (foldr)
import Control.Applicative
import Data.Foldable
type f :~> g = forall a. f a -> g a
nt :: (Functor f, Foldable f, Alternative g) => f :~> g
nt = foldr ((<|>) . pure) empty
Then using tel's xmap
xmap :: (a -> b) -> (f :~> g) -> (f a -> g b)
xmap f n = map f . n
we can do things like
> xmap (+1) nt (Just 1) :: [Int]
[2]