Reputation: 163
I am completely new to Haskell.
I have several layers of information. Each layer is calculated in a unique way, but on the output I have just lists of typed elements.
layer1 :: MyData -> [Element1]
layer1 mydata = unique calculations
layer2 :: MyData -> [Element2]
layer2 mydata = even more unique calculations, using layer1
layer3 :: MyData -> [Element3]
layer3 mydata = completely genious layer of profound information
.....
So here my N functions cannot be parametrized and should remain detached.
Then I want to run a bunch of similar functions on these layers.
I mights do it in a straightforward way
transform1 :: MyData -> [Int]
transform1 mydata = zipWith f (layer1 mydata) constList
transform2 :: MyData -> [Int]
transform2 mydata = zipWith f (layer2 mydata) constList
transform3 :: MyData -> [Int]
transform3 mydata = zipWith f (layer3 mydata) constList
......
But here clearly it is inviting to make some kind of unification. Like
universalTransform :: Layer -> [Int]
universalTransform layer = zipWith f layer constList
Ok. So now I need to make Layer
abstraction
data Layer = Lay1 [Element1] | Lay2 [Element2] | Lay3 [Element3]
data LayerName = Lay1Name | Lay2Name | Lay3Name
Then I need to make a dispatching collector
take :: LayerName -> MyData -> Layer
take lname mydata = case lname of
Lay1Name -> Lay1 (layer1 mydata)
Lay2Name -> Lay2 (layer2 mydata)
Lay3Name -> Lay3 (layer3 mydata)
And somehow it becomes huger and huger and the worst problem is that my zipWith f
wants a list. And in universalTransform
layer
is not a list. It is a Layer
abstraction. I was trying to befree [ElementsX]
from inside of Layer
but didn't succeed.
I know I am looking in a wrong direction.
So: how can I do that unification, but in a proper way, and not like ...ehmmm... me myself.
Upvotes: 2
Views: 144
Reputation: 34378
As Alexis King points out, you don't need the Layer
type to abstract over the transformations. Just have your function take f
and the layer function as arguments. That way, you go from...
transform1 :: MyData -> [Int]
transform1 mydata = zipWith f (layer1 mydata) constList
... to (let's say the type of constList
is [Foo]
):
transform :: (a -> Foo -> Int) -> (MyData -> [a]) -> MyData -> [Int]
transform f layer mydata = zipWith f (layer mydata) constList
This transform
becomes easier on the eyes if you flip the order of the arguments of f
:
transform :: (Foo -> a -> Int) -> (MyData -> [a]) -> MyData -> [Int]
transform f layer mydata = zipWith f constList (layer mydata)
Now it becomes easy to not mention mydata
explicitly (this final step is perhaps a matter of taste, but I like it best this way):
transform :: (Foo -> a -> Int) -> (MyData -> [a]) -> MyData -> [Int]
transform f layer = zipWith f constList . layer
The main substantial difference between transform
and what you were speculating about doing with Layer
is that with this solution you are not constrained to just three ways of creating the layers, as specified by LayerName
. Given how you stated your problem, however, I guess you didn't really want such a restriction in the first place.
P.S.: If you actually wanted something similar to your Layer
proposal (which, again, is something I strongly suspect you don't actually need), you would probably have better luck with something like...
data Element = Elem1 Element1 | Elem2 Element2 | Elem3 Element3
... plus a layer-producing function (that actually produces a list!):
toLayer :: LayerName -> MyData -> [Element]
The function you give zipWith
would then be responsible for doing case analysis on Element
:
f :: Foo -> Element -> Int
Upvotes: 3