Reputation: 97
I want to deal with an abstraction where I can store f1, f2, f3, f4, f5... where
:t f5 . f4 . f3 . f2 . f1
-- String -> Int
I don't much care for the intermediary results, so I would like to do something like:
data PipeFunction a z = [(a->b), (b->c), ..., (y->z)] -- pseudocode
What kind of abstractions would allow me to do this? Right now the only thing I can think of is:
newtype PipeFunction a b c = PipeFunction (a->b, c->d)
but I would like it to be for arbitrary number of functions.
EDIT: A potentially illustrating example/use case, having an abstraction that allows me to perform this more elegantly:
EDIT2: Follow-up. Is it possible to swap out elements of a type-aligned sequence? Working off of something like this:
swapPipe :: PipeFunction a z -> Int -> (b -> c) -> PipeFunction a z
swapPipe Nil _ _ = Nil
swapPipe (f :> fs) i g = f :> swapPipe fs i g
swapPipe (f :> fs) 0 g = g :> fs
Would dependent types in something like Idris be of use?
Upvotes: 1
Views: 158
Reputation: 48672
You can store them with a GADT, like this:
{-# LANGUAGE GADTs #-}
data PipeFunction a z where
Nil :: PipeFunction a a
(:>) :: Show b => (a -> b) -> PipeFunction b z -> PipeFunction a z
infixr 5 :>
And the example from your question:
import Data.Function
import Data.List
showPipe :: PipeFunction a z -> a -> [String]
showPipe Nil _ = []
showPipe (f :> fs) x = show y : showPipe fs y
where y = f x
main = print $ showPipe (sort :> group :> sortBy (flip compare `on` length) :> head :> head :> Nil) [3,1,2,2,3,5,5,6,3,5,5,3]
-- Result: ["[1,2,2,3,3,3,3,5,5,5,5,6]","[[1],[2,2],[3,3,3,3],[5,5,5,5],[6]]","[[3,3,3,3],[5,5,5,5],[2,2],[1],[6]]","[3,3,3,3]","3"]
Upvotes: 5