Is there a way to unblock Haskell?
I am writing a Haskell program. I created a datatype called dimension which is an array of doubles, it looks like this:
data Measurement = Measurement [Double] deriving (Show)
I have a drop function in Measurement, it takes a list of doubling lists and feeds it to a measurement list. It looks like this:
castToMeasurement :: [[Double]] -> [Measurement] castToMeasurement = map Measurement
But now I want to do some operations on double values. So is there a way I can deal with the array of doubles? So when I give it a Dimension (or a Dimension list), it translates it into a Duplicate list (or a list of doubles lists). Thank!
source to share
Yes there is:
data Measurement = Measurement { getMeasurement :: [Double] } deriving Show
castToMeasurement :: [[Double]] -> [Measurement]
castToMeasurement = map Measurement
castFromMeasurement :: [Measurement] -> [[Double]]
castFromMeasurement = map getMeasurement
Simple, isn't it?
source to share
Well, no and yes.
The way you formulate the question, is there a way to "untie", the answer should be not, not at all. Suppose we have a list of strings:
example1 :: [String]
example1 = ["Hello", "cruel", "world"]
We can use map length
to map this to string lengths:
example2 :: [Int] example2 = map length example -- value: [5, 5, 5]
But there is no way to "unmount" the value example2
to get it back example1
. This would require that there be a function that, given the length, figure out which string the original list has, but that's clearly not enough information!
But this gives us a hint as to what situation we can do the "unmapping" you want. If the function we are initially mapped to has the opposite , then we can match that with the opposite to the "undo" effect map
. In your case, the constructor Measurement
has the inverse:
-- | The inverse of the 'Measurement' constructor. Laws:
--
-- > Measurement (getMeasurement x) == x
-- > getMeasurement (Measurement xs) == xs
getMeasurement :: Measurement -> [Double]
getMeasurement (Measurement xs) = xs
Since Measurement
and getMeasurement
are inverse, it also follows that map Measurement
and map getMeasurement
, and so:
map getMeasurement (map Measurement xs) == xs
map Measurement (map getMeasurement xs) == xs
source to share
Sure. Here you can learn more about it.
Think about a function f
:
f :: [Double] -> Measurement
f list = Measurement list
It just terminates the constructor Measurement
. I use the new function because it is much easier for me to think about the function than the constructors.
Now you need a reverse function for f
:
g :: Measurement -> [Double]
g (Measurement list) = list
So now you can build a function:
castFromMeasurement :: [Measurement] -> [[Double]] castFromMeasurement = map g
It looks a little ugly. Therefore, we can change it using lambdas:
castFromMeasurement :: [Measurement] -> [[Double]]
castFromMeasurement = map (\(Measurement list) -> list)
But note that it only works when your data type is not abstract (you have full constructor access). Also you can override your data like this:
data Measurement = Measurement { getMeasurement :: [Double] } deriving Show
In this case, you already have a function g = getMeasurement
. So castFromMeasurement
it looks like this:
castFromMeasurement :: [Measurement] -> [[Double]] castFromMeasurement = map getMeasurement
More generally, you can unmap
if and only if the function f
you used to display is reversible.
source to share
You have the answer to your question, but let him bring the math to the table and find out when and how to undo it.
We are pure functional programmers; this means that the functions we write are very mathematical (which is not much for many reasons, one of them: you can write this answer). When working with functions, the domain of functions is any possible value of the input type (+ bottom for nested types). The range, as well as all possible values ββof the output type.
What you are basically asking for is the inverse function for the function in your example ( fmap Measurement
).
A function inverse for a function will "undo" what that function has "done".
If I have a value x
and a function f
, and the inverse function f
is equal g
, then by definition x = f(g(x))) = g(f(x)))
. This is probably gibberish, so think about the functions f = (+1)
and g = subtract 1
and pick any integer for x
. Let's say, for example x=5
. f(5) = 6
and now notice how when applying g
- g(6) = 5
- you got the number you started with.
You are "frustrated" f
applying the result to g
because it g
is an inverse f
.
Some functions do not have an inverse function (as Luis Casillas said in his answer ).
When your function is actually there, you can find it. If it really is possible, it is usually as complex as the function you are calling (for example, as above, plus becomes minus. As in your example - your function was simple, so the reverse should have been simple as well).
An easy way to determine if there is an inverse function is to see if there is a one- to -one mapping between domain and range. If not, you lost data when you applied this function and you cannot go back. So if the reverse function doesn't exist and you need to return anyway, you must find other means. For example. zip the original value before start ( (x, f x)
), and to get the original value just apply fst
.
Inverse functions on Khan Academy
Inverse functions on TheMathPage
Inverse functions on Wikipedia
source to share