有没有办法在Haskell中取消映射?

时间:2014-12-30 13:43:23

标签: haskell

我正在写一个Haskell程序。我创建了一个名为measurement的数据类型,它是一个双精度数组,它看起来像这样:

data Measurement = Measurement [Double]  deriving (Show)

我有一个强制转换为Measurement的函数,它会获取双精度列表的列表,并将其转换为测量列表。它看起来像这样:

castToMeasurement :: [[Double]] -> [Measurement]
castToMeasurement = map Measurement

但现在我想对双值进行一些操作。那么有没有一种方法可以取消映射到双打数组?因此,当我给它一个Measurement(或测量列表)时,它会将它转换为双打列表(或双列表列表)。谢谢!

4 个答案:

答案 0 :(得分:6)

是的,有:

data Measurement = Measurement { getMeasurement :: [Double] } deriving Show

castToMeasurement :: [[Double]] -> [Measurement]
castToMeasurement = map Measurement

castFromMeasurement :: [Measurement] -> [[Double]]
castFromMeasurement = map getMeasurement

简单,不是吗?

答案 1 :(得分:6)

嗯,不,是的。

你说出这个问题的方式,是否有一种“取消映射”的方法,答案必须是否定的,而不是一般的。假设我们有一个字符串列表:

example1 :: [String]
example1 = ["Hello", "cruel", "world"]

我们可以使用map length将其映射到字符串的长度:

example2 :: [Int]
example2 = map length example
-- value: [5, 5, 5]

但是无法“取消映射”example2的值以取回原始example1。那将需要一个函数,根据长度,找出原始列表中的字符串 - 但这显然是不够的信息!

但这给了我们一个暗示我们可以执行你想要的“取消映射”的情况。如果我们最初映射的函数具有,那么我们可以使用该逆映射来“撤消”map的效果。在您的情况下,Measurement构造函数确实有一个逆:

-- | The inverse of the 'Measurement' constructor.  Laws:
--
-- > Measurement (getMeasurement x) == x
-- > getMeasurement (Measurement xs) == xs
getMeasurement :: Measurement -> [Double]
getMeasurement (Measurement xs) = xs

由于MeasurementgetMeasurement是反转的,因此map Measurementmap getMeasurement也是如此,所以:

map getMeasurement (map Measurement xs) == xs
map Measurement (map getMeasurement xs) == xs

答案 2 :(得分:4)

当然可以。 Here您可以阅读更多相关信息。

让我们考虑函数f

f :: [Double] -> Measurement
f list = Measurement list

它只包装了Measurement的构造函数。我正在使用新函数,因为我更容易思考函数而不是构造函数。

现在你需要f的反函数:

g :: Measurement -> [Double]
g (Measurement list) = list

所以现在你可以构建函数:

castFromMeasurement :: [Measurement] -> [[Double]]
castFromMeasurement = map g

看起来有点难看。所以我们可以使用lambdas修改它:

castFromMeasurement :: [Measurement] -> [[Double]]
castFromMeasurement = map (\(Measurement list) -> list)

但请注意,只有当您的数据类型不是抽象的时(您对构造函数具有完全访问权限),它才有效。您也可以按如下方式重新定义数据:

data Measurement = Measurement { getMeasurement :: [Double] } deriving Show

在这种情况下,您已经拥有了函数g = getMeasurement。所以castFromMeasurement看起来像是:

castFromMeasurement :: [Measurement] -> [[Double]]
castFromMeasurement = map getMeasurement

更一般地说,当且仅当您用于映射的函数unmap可以反转时,您才能f

答案 3 :(得分:3)

你得到了一个问题的答案,但让我们把数学带到桌面,了解何时以及如何取消映射。

我们是纯粹的功能性程序员;这意味着我们编写的函数是非常数学的(由于很多原因,其中之一是超出了可能性:其中一个可以写出这个答案)。处理函数时,函数域是输入类型的每个可能值(盒装类型的+底部)。同样,范围是输出类型的每个可能值。

您基本上要求的是示例中的函数inverse functionfmap Measurement)。
函数的反函数将“撤消”该函数“做”的内容 如果我有值x和函数f,并且f的反函数是g,那么按定义x = f(g(x))) = g(f(x)))。这可能是胡言乱语,所以请考虑函数f = (+1)g = subtract 1,并选择x的任何整数。我们假设x=5为例。 f(5) = 6,现在注意当你申请g - g(6) = 5时 - 你得到了你开始时的号码。
你“解除了”f将结果应用于g,因为gf相反。

有些函数没有反函数(正如Luis Casillas在his answer中所示) 当你的功能确实有,你可以找到它。如果确实可能的话,通常它就像你正在反转的函数一样困难(例如,如上所述,加上变为负数。就像在你的例子中一样 - 你的函数很简单所以逆也必然很简单。)

判断是否存在反函数的简单方法是查看域和范围之间是否存在one-to-one mapping。如果没有 - 您在应用该功能时丢失了数据而无法返回。因此,如果不存在反函数并且您仍需要返回,则应该找到其他方法。例如。先前压缩原始值((x, f x)),并获得原始值只需应用fst

Inverse Functions on Khan Academy
Inverse Functions on TheMathPage
Inverse Functions on Wikipedia