如何证明函子的MAP方法的关联特性

时间:2018-12-26 13:44:17

标签: javascript functional-programming functor

我了解到函子的地图具有关联性,并且暗示以下内容:

Functor.map(f).map(g) == Functor.map(x => g(f(x))

上面的方程式不是应该这样写才能证明关联性吗?

Functor.map(f).map(g) == Functor.map(f.map(g))

(但是它不可能缝合,因为函子没有map方法)。

有些东西我在这里没有掌握。

1 个答案:

答案 0 :(得分:0)

这是Haskell中的示例。
您可以创建两个函数。 第一个composeAndMap将首先组成fg,然后应用map函数。

composeAndMap :: Functor f => (b -> c) -> (a -> b) -> f a -> f c
composeAndMap f g = fmap (f . g)

第二个将称为mapAndCompose,它将使用map函数组成两个部分应用程序函数。第一个地图将使用f,第二个地图将使用g,如下所示:

mapAndCompose :: Functor f => (b -> c) -> (a -> b) -> f a -> f c
mapAndCompose f g = fmap f . fmap g

最终,您可以使用特定的仿函数实例在每个函数的结果之间进行比较,最明显的是列表仿函数。

list :: [Int]
list = [1..5]

main :: IO ()
main = print $ mapAndCompose (+1) (+2) list == composeAndMap (+1) (+2) list

您也不应该忘记身份法。

identity :: Functor f => f a -> f a
identity = fmap id

composeAndMap :: Functor f => (b -> c) -> (a -> b) -> f a -> f c
composeAndMap f g = fmap (f . g)

mapAndCompose :: Functor f => (b -> c) -> (a -> b) -> f a -> f c
mapAndCompose f g = fmap f . fmap g

list :: [Int]
list = [1..5]

main :: IO ()
main = do 
  print $ identity list == list    
  print $ mapAndCompose (+1) (+2) list == composeAndMap (+1) (+2) list

这是JavaScript中的示例:
创建两个函数plusOneplusTwo

function plusOne(val) {
    return val + 1;
}

function plusTwo(val) {
    return val + 2;
}

创建一个由两个功能组成的compose函数

function compose(f, g) {
    return (val) => f(g(val));
}

创建实用程序功能sequenceEquals

function sequenceEquals(arr1, arr2) {
    for (var i = 0; i < arr1.length; i++) {
        if (arr1[i] !== arr2[i]) {
            return false;
        }
    }

    return true;        
}

现在您可以在两种实现方式之间进行比较:

let list = [1,2,3,4,5];
let composed = compose(plusOne, plusTwo);
let composeAndMap = list.map(composed);
let mappedTwice = list.map(plusTwo).map(plusOne);

console.log(sequenceEquals(composeAndMap, mappedTwice));

还有身份法。
创建一个身份函数:

function identity(value) { return value; } 

比较结果:

console.log(sequenceEquals(list.map(identity), list));