我正在写一个Haskell程序。我创建了一个名为measurement的数据类型,它是一个双精度数组,它看起来像这样:
data Measurement = Measurement [Double] deriving (Show)
我有一个强制转换为Measurement的函数,它会获取双精度列表的列表,并将其转换为测量列表。它看起来像这样:
castToMeasurement :: [[Double]] -> [Measurement]
castToMeasurement = map Measurement
但现在我想对双值进行一些操作。那么有没有一种方法可以取消映射到双打数组?因此,当我给它一个Measurement(或测量列表)时,它会将它转换为双打列表(或双列表列表)。谢谢!
答案 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
由于Measurement
和getMeasurement
是反转的,因此map Measurement
和map 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 function(fmap 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
,因为g
与f
相反。
有些函数没有反函数(正如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