【翻译】Mostly Adequate Guide to Functional Programming : chapeter 11-12

原文地址:https://mostly-adequate.gitbooks.io/mostly-adequate-guide/

前十章中文翻译:https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/

说明:

  • 编程/计算机基础较弱,理解不到原作者的深度,翻译一定会有问题,尽量在自己成长的同时保持更新。
  • 英语也弱,try my best,也是保持更新/修复。
  • 只讲重点,不会像前十章翻译那样直译,觉得无关紧要的引用或叙述,统统做总结简述。

第11章 自然转换

诅咒嵌套

此嵌套指:两种以上的类型将一个值包裹起来,如下

Right(Maybe('b'));

IO(Task(IO(1000)));

[Identity('bee thousand')];

一个情景喜剧

// getValue :: Selector -> Task Error (Maybe String)
// postComment :: String -> Task Error Comment
// validate :: String -> Either ValidationError String

// saveComment :: () -> Task Error (Maybe (Either ValidationError (Task Error Comment)))
const saveComment = compose(
  map(map(map(postComment))),
  map(map(validate)),
  getValue('#comment'),
);

有多种方案解决这个常见的问题:将多重类型组合成一个巨大的容器、排序和join、同质化、解构等等。这章我们集中在通过自然转换同质化它们。

纯天然

自然转换是函子间的态射,意即:作用在容器上的函数。它是一个函数:(Functor f, Functor g) => f a -> g a。特别之处在于,无论如何,我们不能偷看函子的内容。把它想象成高级机密的交换。这是一个结构上的操作,一个函子的变装。正式来说:自然转换是使以下成立的任意函数。

naturalTransformation.png

用代码表示如下:

// nt :: (Functor f, Functor g) => f a -> g a
compose(map(f), nt) === compose(nt, map(f));

示意图和代码都说明了同一件事情,先自然转换然后map或者先map然后再自然转换,可以得到同样的结果。附带说明,这来自自然定理,只不过自然转换(和函子)没有限制函数的类型。

坚持原则的类型转换

程序员都很熟悉类型转换。我们将Strings转换成Boolens,Integers转换成Floats(JS中仅有Numbers)。不同之处在于,这里我们在处理代数容器,并且用一些理论去处理。
先看一些例子

// idToMaybe :: Identity a -> Maybe a
const idToMaybe = x => Maybe.of(x.$value);

// idToIO :: Identity a -> IO a
const idToIO = x => IO.of(x.$value);

// eitherToTask :: Either a b -> Task a b
const eitherToTask = either(Task.rejected, Task.of);

// ioToTask :: IO a -> Task () a
const ioToTask = x => new Task((reject, resolve) => resolve(x.unsafePerform()));

// maybeToTask :: Maybe a -> Task () a
const maybeToTask = x => (x.isNothing ? Task.rejected() : Task.of(x.$value));

// arrayToMaybe :: [a] -> Maybe a
const arrayToMaybe = x => Maybe.of(x[0]);

看出来没?将一个函子转换成另一个函子,我们可以在过程中丢失一些信息,只要保证没有在形式转换中丢失将要map的value即可。这就是关键点:根据我们的定义,map必须可以持续下去,甚至是在转换结束之后,还可以继续。

从转换效果的角度观察,ioToTask可以认为是同步到异步的转换,arrayToMaybe是非确定性到可能失败。注意在JS中我们不能从异步转换到同步,所以我们不能写taskToIO - 那将是超自然转换。

Feature Envy

假设我们需要再List上使用其他类型的特性,比如sortBy。自然转换提供一个很好的方式转换成目标类型。

// arrayToList :: [a] -> List a
const arrayToList = List.of;

const doListyThings = compose(sortBy(h), filter(g), arrayToList, map(f));
const doListyThings_ = compose(sortBy(h), filter(g), map(f), arrayToList); // law applied

同构Javascript

当可以完全的来回调用而不丢失任何信息,这就是同构。
如果我们可以提供自然转换作为证据,我们就可以说两种类型是同构的。

// promiseToTask :: Promise a b -> Task a b
const promiseToTask = x => new Task((reject, resolve) => x.then(resolve).catch(reject));

// taskToPromise :: Task a b -> Promise a b
const taskToPromise = x => new Promise((resolve, reject) => x.fork(reject, resolve));

const x = Promise.resolve('ring');
taskToPromise(promiseToTask(x)) === x;

const y = Task.of('rabbit');
promiseToTask(taskToPromise(y)) === y;

Promise和Task是同构的,我们也可以写一个listToArray实现arrayToList显示他们是同构。作为一个反例,arrayToMaybe不是同构,因为它丢失了信息。

// maybeToArray :: Maybe a -> [a]
const maybeToArray = x => (x.isNothing ? [] : [x.$value]);

// arrayToMaybe :: [a] -> Maybe a
const arrayToMaybe = x => Maybe.of(x[0]);

const x = ['elvis costello', 'the attractions'];

// not isomorphic
maybeToArray(arrayToMaybe(x)); // ['elvis costello']

// but is a natural transformation
compose(arrayToMaybe, map(replace('elvis', 'lou')))(x); // Just('lou costello')
// ==
compose(map(replace('elvis', 'lou'), arrayToMaybe))(x); // Just('lou costello')

它们确实是自然转换,因为在任何一方map都会产出同样的结果。

更广泛的定义

这些结构化的函数并不限制通过任何方式进行类型转换。
这有几个不同的例子。

reverse :: [a] -> [a]

join :: (Monad m) => m (m a) -> m a

head :: [a] -> a

of :: a -> f a

自然转换规则也支持这些函数。

一个嵌套的解决方案

第12章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 看了张艺谋的《影》,艺术又极具中国美,水墨贯彻得丰满,雨一直不停,又过于阴郁,最后的情节反转,拍的挺棒。在中国,普...
    贾的假不了阅读 151评论 0 0
  • 1937——1945年,在日本侵华战争期间,至少20万中国女性被日本掳抢为“慰安妇”。2012年,中国只剩32位勇...
    一个树洞婆婆阅读 365评论 0 0
  • 时间如流水,流到哪里去? 不知道。 画中的小女孩,属马,2002年出生的,今年高二了。 这时间的飞逝,不看旧照,还...
    鲁长安阅读 175评论 1 0
  • 知识点 输出格式问题 如果没有特殊的格式要求,直接 cout 即可 代码
    欢城深喟阅读 559评论 0 0