精神病人思维广

想得太多,读得太少

传染性与致死性

从“自私的基因”角度来看的话,增强传播性强才是病毒演化的方向吧?致死率应该从来都不是?毕竟传播性强,则基因得以增殖;致死率高,则对其不利 🤔。

所以病毒最好的演化方向应该是长期寄宿于宿主,对宿主没有什么影响但难以清除,又一直具有传染性?

所以 Omicron 这种高传染性低死亡率的变异株是巧合?是物竞天择?

2022 年 4 月 11 日

身在汉营心在曹

如果有身在汉营心在曹这个词,它的含义会与“身在曹营心在汉”相同吗?还是说相反?

就语法结构来说,它们似乎是等价的,含义应该相同。
但从语义来说,考虑到下面的解释

身在曹营心在汉:比喻身处对立的一方,但心里想着自己原来所在的一方。

似乎可以又有着“曹营:对立一方”以及“汉:原来一方”这样的绑定关系。以此为依据,那“身在汉营心在曹”似乎又应该是类似“吃里扒外”的意思,这样含义就变得相反了。

语法解读与语义解读不等价呢

2022 年 04 月 1 日

认识到一些永恒性

感觉近两年自己的脾气越来越好了。

  1. 比如别人问一些简单的问题时表面上和心里都不会生气。(以前其实挺烦的,心理活动:你™不会百度吗?)
  2. 比如有人迟到挺久也不会生气——只要还能赶上高铁与飞机。
  3. ……

为什么呢?之前读到过一个研究:说是人生气与否,或者说任意感情波动,不取决于某件事的“绝对好坏”,而是取决于“相对好坏”,即绝对好坏与自己的预期的差值。所以大概是随着年龄的增长,对别人、对万事万物的预期都变得很低的缘故。

由此,也觉得自己真的认识到了一些永恒性。

  • 例如之前一直认为授之鱼不如授之以渔,但现在经常会打消这个念头。近年来会感觉到有些人就是不愿意也不可能去学习,不愿意也不可能去接纳新生事物和新想法(最起码的尊重也做不到)。对于前者,原因大概是对那些人来说,学习新东西是痛苦的,他们不想学习,也不想思考复杂的问题。(虽然对我来说,学习新东西是总是令人愉悦的。)

  • 那么,也就认识到了另一种永恒性,比如说周围的一些人就是不如自己。不仅过去(近期)不如,现在不如,并且以后也不如。不学习、不思考,也是要付出代价的。当然了,这也许是因为他们过去的经历造成的,而过去的经历又是与智力水平以及周围环境相关的,这与长得好看不好看其实也没太大本质区别。因此,趁早感恩、报答社会吧;共同富裕很有必要。当然了,顽固不化的人也不能太阻碍新兴事物。

2022 年 3 月 28 日

自觉

“中国人在国外要比在国内更有自觉,一刻也不能松懈,因为没做好的话整个国家的人都会被诟病。”

其实大公司的领班在外面也是要有点自觉的:如果自己在外面表现得足够垃圾,那整个公司也就会被诟病,真是巴不得早点倒闭

2021 年 10 月 20 日

2022 年 02 月 07 日

alt 纪念空洞骑士

我很少为游戏写点什么,至少最近几年内没有对这种事儿的印象。

但对于“抽出”了一整个春节假期才打通的《空洞骑士》(Hollow Knight),我觉得还是可以稍微记录一下的:剧情设定,美术,音乐(以及难度),都比较合我胃口;据说游戏团队只有三个人。

说是抽出了一整个春节假期,倒不如说是春节假期的时间完全被它抽空。外面阴雨连连,房间里灯火阴暗,游戏里“暗无天日”(虫虫不喜欢光)。

alt 空洞骑士游戏统计

游戏的基本设定

主角与其他一切皆为昆虫(广义上),昆虫组建了类似人类现在文明程度的高度分化的社会,其中有几方势力,而主角所属的势力被称为圣巢。

故事发生在圣巢全盛之后的衰败期,“瘟疫”扩散并感染了很多圣巢的虫群。玩家醒来,作为空洞骑士,目的就是阻止瘟疫。PS:游戏虽然是碎片化叙事,但还是很有深度的。故事我不打算讲了,比较长,只说几点:我能在其中看到人类社会的缩影,比如曾经的盲目信仰,“虫”本主义,集体主义,个人主义,阶级分层,各种战争,瘟疫和被忘却的历史()……我看得到些许非常极端也极具个性的非主线 NPC,例如锻造出完美骨钉后以身试刃寻死的()(不砍他的话,他之后会转行绘画,且也会为当时的冲动后悔),被洗脑后说着“你看我多白多胖,鲜嫩多汁”专门作为其他虫虫的食物的虫子(),以及头都插地了还骂骂咧咧的菜鸡()……我看不到所谓的“正能量”和(所谓的)“价值观输出”。(偶尔还是有,例如这个这个,和这个。)

游戏是 2D 平面动作类游戏,含有(二段)跳跃,(超级)冲刺,平砍,剑技,(灵魂、虚空)魔法,符文等可操作性要素,组合起来还是挺复杂的。游戏的基本玩法是探索巨大的地图,神挡杀神、佛挡杀佛,最终阻止瘟疫。

印象深刻的部分

从这里开始,基本等同于我™“吹爆”——当然了,大概只是因为我玩过的游戏比较少

叙事

虽然说是碎片化叙事吧,里面 NPC 的话也不算少,在剧情的任一阶段,连续对话两三次基本都是新对话而不是重复同一句话;而通过梦之钉攻击 NPC 和 160 来种“可被攻击的昆虫”,也能看到对话;基本就是说只要是活的东西都能触发对话;哦不对,死的尸体也行……

此段剧透,影响游戏体验 下文会提到令人痛苦和抓狂的跳跃关,但它其实也是游戏性叙事。必跳的关卡只发生在游戏的最后阶段,我认为它其实是揭示了白王是如何挑选合适的容器的。正是因为这条路是如此的艰辛,玩家也会更容易对后面的剧情产生共鸣

此段剧透,影响游戏体验 个人感觉还有点元叙事的意思,不过肯定是可能是过渡解读了:该如何制造一个莫得感情的空洞容器,游戏中给了解答——“生于神与虚空之手”;但这样一个“没有可以思考的心智,没有可以屈从的意志,没有为苦难哭泣的声音”的空洞容器为何可以行动呢?是不是靠屏幕外面的玩家呢?或者说,反过来想,假如空洞容器是有自我意识的,他为什么听从玩家操控而不自己行动呢?

地图设计

因为属于探索类游戏,所以地图巨大:至少也有十来个小区域,每个小区域内又有十几个小图,而游戏团队在如此庞大的地图上做到了下面几点。

  • 小区域具有多样性,且主题鲜明——类似于魔兽里的部落和联盟会是迥然不同的风格那样,这个游戏里有十来种。每个小区域的怪物设计、背景音乐、美术也为游戏加了很多分。每个小区域的小怪、精英怪、boss 基本不带重样。
  • 在如此庞大的地图上,需要兼顾和平衡好前中期探索、中后期跑图省时间两件事:一百多张小地图之间如何(非线性)连通,哪些技能可以开启新图,什么时候开启省跑图时间的功能,是一件需要精巧设计与严密逻辑的事儿。说简单点,主路和旁道,也要略作标识。地图隐含各种暗道,暗道内的宝箱这事儿就不提了。
  • 地图过渡自然,不同区域邻接处有明显的过渡和中间带。且不仅仅只是美术场景的过渡,也有小区域象征性元素(如图腾)和音乐的过渡。例如有个区域即使起了“军事冲突”电车也修不过去,那邻接的场景元素就包括了成堆的武器、尸体等。

要不预览一下全图别认真看,有轻微剧透。

alt 空洞骑士全地图

是否感受到了“完整与庞大”,以及“昔日的繁华”?

游戏操作和难度

比起快餐年代的 click 智障游戏,这游戏的难度可以用地狱来形容了吧。没有类似游戏经验的新手玩家,前期金钱归零以及一个 boss 打十几次应该是家常便饭。

精英怪

用剑的话,莽,是不可能的,比如观察其动作模式并反制。手残可以选择法术流或者召唤流混过去。

Boss 战

同上,莽,是不可能的。不同上,不少 boss 无法用法术流以及召唤流卡地形混过去(俗称逃课)。找准 boss 的行为模式并在极限反应时间内采取反制行动才是正确做法。且由于一些 boss 战配乐以及 boss 踩鼓点的行为,以及让人感到绝望的手指协调性考验(是不是按的键总是与自己想的不太一样?),让该游戏被戏称为“音游”。

  • 上面说的对战技巧,游戏会循序渐进地教给我们,例如螳螂领主,被称为考官,过了即为游戏正式入门。详情请见知乎长文。我这还有个自己录的手残视频

  • 比如打失败冠军,就得知道 boss 往前跳,往后跳,往墙跳,往中间跳之后接续的招式(逃课除外),才知道怎么走位和规避。手残视频戳此

  • 教会我们一个人生哲理——“逃避是没有用的”:一些 boss 基本只能保持中近距离以及“对冲换位”来打,因为恐惧而尝试拉远距离就是必死。比如大表哥失落近亲的被戏称为“因果律大跳”的前跳,尝试拉远距离时,该跳跃会根据跳跃上升期间玩家的行动来自动计算和调整落地位置……分析视频戳此。手残视频戳此。又如收藏家的下落瓶,是需要通过观察屏幕上方烟雾来躲的,瞎走位就会觉得有必中的错觉,十分玄学;手残视频戳此

跳跃关

与 boss 战一样,属实地狱难度,同时考验了游戏里的各种组合键、观察与逻辑推理、极限反应时间以及手指协调性。普通跳跃本身的高度就会根据按跳跃键时间的长短有着极大区别,跳跃 + 冲刺组合成的空中冲刺更是拉大了跳跃高度的区别。后期还糅合了二段跳,贴墙 + 跳,贴墙 + 超级冲刺,下劈弹起 + 跳or冲刺。这种一秒左右连按 8 键的事,直接教我重新做人:跳z + 左← + 攻击x + 右→ + 贴墙+ 跳 z + 左← + 冲刺 c + 二段跳 z……(还说不是音游?)

来云一把必过关卡白色宫殿(时隔 4 年,怎么还有 22 个人在看)。

最难但非必过的苦痛之路

苦痛之路,闲得没事干的每天折磨自己刷世界纪录的(快递员,还是中国的快呀)。

美术、氛围感

游戏的美术非常好,虽然只是简单几何图形与粗贴图的组合;其重在“写意”而不是“工笔”,对于 3 人小团队制作可以说是策略得当、非常合适。

  • 本身具有美感。

  • 美术提高了场景的氛围感。每个场景均有其代表性的图层作为背景,有其代表性的色调色系(可能在乱用词,我不是美术专业的),例如“瘟疫黄”、“乌恩绿”、“国王白”……而不是很多游戏的“清一色”。

  • 美术和场景暗示了剧情与道具、技能获得方式。例如深渊尖啸获得的地方四周都画有其原始技能嚎叫幽灵释放后的画面。

    alt 深渊尖啸

  • 美术与叙事和游戏性结合,欺骗玩家:

    你看到了自己?你要救他?你以为是什么?

    alt 诺斯克 01

    其实是什么?面具倒过来就成了牙齿!

    alt 诺斯克 02

顺便说句玩笑话,每一个大师级作品:

alt Gris 下落

都有许多拙劣的模仿:

alt 空洞骑士下落

音乐、氛围感

如同对美术一样,我对音乐也是一窍不通,只能靠感觉——“我非常喜欢该作品的音乐”,甚至是每一首。也许是听多了?感觉大部分游戏里能找到一两首好听的音乐就差不多了,三四首就是很多了,也有一首都不喜欢玩了个寂寞的(例如当年《永远的伊苏 F》。)

只能说一点我的观察。

  • 音乐与地图主题契合这一点还可以展开说。例如其音乐在地图的不同位置强弱不同,甚至会混入一些“装饰音”;在被击打后会短暂淡出淡入等。各种细节拉满。例如泪水之城的音乐,室内、室外、下雨时、歌手家里各有不同;水晶山谷在不同高度亦有相应变化。例如假骑士的 boss 战音乐,明显能听出(假骑士渴望的)“力量”的感觉,锤子捶地就是重音和鼓点的时候,真棒。再例如打收藏家的时候,因为收藏家本身是个变态,连曾经熟悉的一首音乐也走形畸形变得怪异起来了。
  • 音乐,平淡中有它的骚。与小姐姐大黄蜂的战斗音乐居然还是个弦乐四重奏。好家伙,我是见都没见过,你确定你是 3 人制作的游戏?(PS:而且弦乐可能本来就适合“蜂”这个主题,例如野蜂飞舞?)
  • 不说了,我™能听 100 年。

(另外想评论两句“很多人觉得古典就是好”这事儿。古典很多时候连版权费都免了,在省钱上确实是件好事儿但,一是别人的古典与新艺术作品的剧情能那么契合吗,二是现在的一些作品几百年后是不是也就流芳百世成经典了呢?)

真实与恶意

此段剧透,影响游戏体验 连续死亡两次后金钱会清零的游戏里,好不容易找到一家银行,这下总归安全了吧……结果呢,存少了还好吧;存多了后,开银行的会卷钱跑路过上纸醉金迷的生活……简直是满满的恶意 😂。

此段剧透,影响游戏体验 然后,这个椅子居然能坐,也不知道算不算“恶意”,明明游戏都快到最后了……防剧透,自己点开这张这张图吧。

细节

剧情、游戏性、美术、音乐上的细节实在是太多了。当时比较匆忙,没有截图。只能自己体验了。

3 人团队制作

这么多内容的一个游戏,3 个人(不加班)就搞出来了?给“某些大厂” 30 个人的团队,做得出来吗?

除了经验丰富外,我认为也离不开扬长避短的设计策略:侧重于多样性与组合性。例如没有选择 3D 而选择了 2D,省去了大量贴图美术与性能优化的时间吧;选择写意烘托氛围而不是工笔,应该也省去了大量的时间吧。算是把时间和钱都砸在刀刃上了。我们看看国内大厂在做什么呢——大概是在做可以舔的人物皮肤和抽卡吧。

2021 年 11 月 10 日

后疫情时代,外循环出奇地好,而内循环却不太行了。还请各位在较为宽松的货币政策下,在投资夜壶经济和泡沫经济之余,多多消费拉动内需呀。

消费归消费,该薅的羊毛还是得薅。

请问各位是如何薅羊毛的呢? 元或者 元购物?优惠券满减?又或是信用卡返现?

或者换个问题,在网店买一件商品,最多能享受几次折扣呢?我给出的答案是(至少) 次:

  • 网店平台(京东,淘宝等)提供的折扣
  • 支付渠道(支付宝,微信,云闪付,招行支付等)提供的折扣
  • 支付卡(信用卡,借记卡等)提供的折扣

这三点属于不同层级,所以折扣可以累加。例如你买 块钱的东西,京东提供 ,支付选云闪付,云闪付提供 ,最后信用卡还有个返现或者几毛钱抵扣;那到手价格就是 。且积分也是每个层级分别计算的。

本文的薅羊毛之旅也将围绕这三个层次的折扣展开,并就个人使用情况,做一些推荐。薅羊毛嘛,大体还是图个日常开心吧,毕竟一个月一般也就只能薅到几十块钱。

写给大忙人的结论

因为这个时代大部分人都很忙,所以还是把结论简要写在前面:

  • 第一层次网店平台的折扣,不同平台可能大差不差。且不同用户黏性不同,就提下面亮点,其他不多说。
    • 淘宝的 88vip 很划算。淘宝的省钱月卡看个人情况。
    • 京东会员带有腾讯会员等的一年 左右的比较划算,单买不划算。
  • 第二层次支付渠道的折扣,首推云闪付,次推招行。
    • 云闪付,办理里面的两个 vip 月卡,每个月薅几十块钱。支付宝已经式微。
    • 招行支付,饭票等比旧一代美团每百元至少便宜几块钱。微信支付已经式微。
  • 第三层次支付卡的折扣,我只用过招行,还行。
    • 信用卡我只用过招行的,羊毛还是挺多的;例如 块减几毛的活动基本没断过,且商城里积分可以兑换信用卡还款券。
    • 储蓄卡我基本只用过招行的,羊毛还挺多,每个月固定会送几块钱黄金和几块钱信用卡还款券和几块钱商城券等。(其他银行 app 就用不爽。)

网店平台等提供的折扣

网店实在是算不得新鲜事物了。且各家打斗到现在,提供的折扣也都大差不差了。这里面还要考虑到用户黏性等(各人有各的偏爱),所以本章只说几个我自己用过的觉得划算的吧。

  • 淘宝的 88 vip。随便买卖的老用户 88 块钱一年,带有网易云一年,饿了么一年,优酷一年,以及几十块钱高德优惠券等其他;然后买一部分商品有折扣(估计是天猫的)。且网易云这种支持板绑定他人手机号。我觉得我不上个图的话总有人觉得我在骗人:

    88 vip 可用服务

  • 淘宝的省钱月卡。每个人按月被索取的钱不一样,我是几块钱一个月,就很赚(毕竟我花呗额度只有 ,用户画像应该是屌丝吧……),截至目前为止实打实地省了大概1000 多(找朋友测试过)。看个人情况,如果定力不错、比较理性、愿意对购物按天进行分拆的话十分划算。详细介绍:每天可以领一张 折左右的通用折扣券……各一张,用五张后还能再领一次),有效期是三天。“白天上班忙,没空逛商场”的一个月省下几十块绝对不是问题。而且我已经找朋友测过,我跟他看到的商品价格是一样的,这卡对我没有杀熟,但结算时我可以叠加优惠券。我觉得不上个图的话总有人觉得我在骗人:

    淘宝省钱月卡

  • 京东各种联名 vip(如腾讯视频会员),130 块钱左右一年。京东 vip 的好处:一是很多商品会员价较便宜,二是送免邮券且京东本身物流极快,三是平台反点比较多,所以开了后只在京东买会更赚一些。日常折扣券是 ……这种,每天可以领一张,24 小时有效;需要手动领取(不教,自己搜)。京东声称它帮我省的钱实在是太浮夸了,diss 一下,作为惩罚,不上图。

  • 招行的商城最近几个月经常有 元或者 元白送的垃圾袋、抽纸等;且每个月送一张 元券(可白嫖抽纸)。反正我家的卷纸、抽纸、小包纸巾、垃圾袋基本都是招行送的……信不信由您,抽纸自由:

    招商与抽纸自由,其之一

    招商与抽纸自由,其之二

  • 打车,高德送新人的优惠券挺多的(不送的话就用 12306 里面的高德打),老用户每天 点可以积分兑换,最次也有 块钱减免 的周卡。而且,打车速度快……(我就不打开截图了,留着周末再打开……)

  • 外卖,首推饿了么。饿了么的通用 券基本是永动机:每周周末都有 单送 积分活动,而 积分又能兑 张通用 券。再者,饿了么的券适用范围比美团广,例如奶茶能用。有了招行和饿了么,美团对我来说就只是个骑车软件,车确实还不错。

  • 所有果园都给我滚蛋,特别是 PDD。

支付平台提供的折扣

这可是羊毛最大的地方了。独乐乐不如众乐乐。

  • 云闪付,永远暂时的神。先开个 可享 6 倍积分的那啥 vip ,反正每个月领一张信用卡还款券用掉就回本了。攒着的 6 倍积分大到迪士尼门票,中到网购平台满减,小到信用卡还款券都能换。6 倍积分真的是太多了,我这边随便买买好像就 2-3 万积分了(之后发生退款的话好像积分也不会回收?)……再开个那啥啥 vip,每个月稳定薅十几块钱,想 10 点抢还款券的还有 10 块钱还款券可以拿。这还不美滋滋!趁云闪付还在撒钱攒流量,看我给它薅秃……而且现在云闪付客户不算多,有些券都不用抢的(下图可以看出)。

    云闪付,其之一

    信用卡还款券应该是满 可用(也可能是 )。线下立减估计哪哪都能用吧,反正我公司食堂吃饭都能用……线上支付、指定 app 好像包括了淘宝、京东等,记得在线支付的时候选云闪付全是自动抵扣。

    云闪付,其之二

    积分淘宝满 还是酸爽啊……可以看到,大平台、奶茶店也都有券。支付渠道选云闪付,自动抵扣。哦对了,今年双十一,淘宝买东西,云闪付支付的话满 ,每天 笔,自动抵扣。

    云闪付,其之三

    线下商超包括了罗森、全家等便利店和其他本地便利店,以及大超市。还款券根本同上,根本不用抢。只有下面这个 积分减 块钱的要抢(在某特殊页面里,且 积分是 vip 增送的独立计算的特殊积分)

    云闪付,其之四

    另外云闪付还有售价 元钱的地铁折扣周卡。

  • 招行支付,伺机待发。我就放一张饭票的图,DDDD。其力度,最次每百元也比美团便宜几块钱;其广度,大部分连锁店都有。

    招行饭票

    招行还有影票等。可惜我看电影不是很多,没怎么薅过,未能留下罪证。

    除此之外,招行每个月固定送 3 元12306 券,自动抵扣。送几块钱黄金,多少取决于您存的钱(和金价),我这种人大概是 块钱;送几块钱信用卡还款金,多少取决于您存的钱,我这种人大概是 块钱,送一张商场 元券(可薅纸巾),杭州招行还送全家购物券,一般是满 5 减 5,这个月是满 8 减 8,且每 199 积分可多换一张。好像还有杂七杂八的打车券,公交地铁充值返现等(下图,配合 apple pay + 全国通用的上海公交卡虚拟卡还挺香,毕竟不用解锁手机就能进出地铁站)。

    招行黄金

    Apple Pay 上海公交卡

    最后,积分商城活动的时候别忘了积分兑换信用卡还款金,一般也挺值的,我前几天刚兑了个 元 * 张,每月可用 张。

其实我也没自己找,都是打开 app 弹了个窗,不小心点进去看了看,这一看可不得了……

支付卡片提供的折扣

最后就是支付卡片提供的折扣了。还是推荐搞一张信用卡月均可享受 天免息期

  • 招行的信用卡买苹果产品,官网一般有 期免息。(这还不比花呗和某东白条高到不知道哪里去了?)您问能省多少钱,这只能取决于个人投资能力,有些人 期免息能白嫖,有些人 期免息后可能还亏钱了……(这究竟是为什么呢?因为如果不免息,就不会拿这笔钱去资本市场堵,就不会亏……)
  • 招行的信用卡基本满 减几毛的活动没听过。日常吃饭、外卖刷卡的话,还是能薅一些的。甭管是从云闪付,支付宝,还是微信付的,这些最后如果是使用招行的信用卡支付的话,都是自动抵扣的。

大概也没了,中国的信用卡没啥好说的,不带保险,没啥活动,根本没发展起来(就进入数字支付时代了😂)。

如果感觉用信用卡会多花钱,那么理性方面还需要加强,我就只觉得是白嫖。

于我而言

我觉得我也没花什么时间,就是无意中碰到了云闪付和招行 😂。

(⬇️ 还是投机有意思,这三个月的盈亏完全对冲掉了 ⬇️)

亏冲盈

盈冲亏

类型系统综述

原作者:Luca Cardelli,Microsoft Research

本文改编自 Luca Cardelli 的《Type Systems》的前两章,类型化语言并对内容和顺序做了调整。

在对类型系统分门别类和比较它们的长短处之前,我们不妨仔细读读前人的研究,学究式地讨论与了解

  • 什么是类型?类型化语言与非类型化语言。
  • 类型系统设立的目的,它可以保证什么。
  • 什么是执行错误;安全与行为良好的异同。
  • 需要多大程度的安全——安全与性能的权衡。
  • 如何形式化地描述类型系统。

总述

类型系统的根本目的是防止程序运行过程中出现执行错误,这个非正式的声明激发了对类型系统的研究。它的准确性首先取决于一个相当微妙的问题——什么是执行错误。然而即使解决了这个问题,没有执行错误也是一个相当不简单的性质。我们必须证明所有可以在编程语言中表达的程序都没有执行错误,才能说该语言是类型安全的。(注:原文是 type soundness,译为类型健全;我们使用了更通俗的术语 type safety,即 “类型安全”。)事实证明,在进行相当多的仔细分析后,才可能避免对编程语言的类型健全性提出错误或令人尴尬的声明。而类型系统的分类、描述和研究也已经成为一门正式的学科。

类型系统的形式化需要精确的符号和定义,以及对形式化性质的详细证明(以使人们相信定义确实是妥当的)。有时,这门学科变得相当抽象;但是我们应该始终记住,实用性仍是这些抽象的基本动机:

  • 抽象是出于需要,并且通常可以与具体的直觉相联系;
  • 形式化,作为一门技术,即便不完整地使用也可以达成相当有用的效果。

了解类型系统的主要原则可以帮助语言设计者避免(明显和不明显的)陷阱,看到语言特性彼此之间的独立性或联系,以此使语言设计得更加规范。

如果发展得当,类型系统还可以作为一门工具,以判断语言定义中的(重要部分)是否已经足够明晰——非正式的语言描述(如自然语言,译者注)往往不能足够清晰和详细地说明语言的类型结构,以保证其实现起来没有歧义——同一语言的不同编译器实现了略有不同的类型系统,这是经常发生的情况。此外,许多语言的定义被发现是类型不安全的,即使程序被类型检查器判定为可以接受,也会导致程序崩溃。理想情况下,形式化类型系统应该是所有带类型的编程语言的定义的一部分。这样一来,就可以根据精确的规范来衡量类型检查算法。而且,如果可能与可行的话,整个语言都可以被证明是类型安全的。

接下来,我们会非形式化地介绍类型、执行错误和其相关概念。我们讨论类型系统的预期性质和好处,并回顾类型系统如何被形式化。我们使用的术语并不是完全标准的;这是由于来自不同来源的标准术语的内在不一致性造成的。在提到运行时概念时,我们用动态检查来代替动态类型,并避免使用强类型这样常见但含糊的术语。

类型的基本概念

类型

在程序的执行过程中,一个程序变量可以承担一定的数值(数据)范围。这种范围的上限被称为该变量的类型。例如,一个布尔类型的变量 x 应该在程序的每次运行中只承担布尔值。如果 x 是布尔类型,那么布尔表达式 not(x) 在程序的每次运行中都有合理的意义;如果 x 承载了布尔以外的值,例如字符串,那么布尔表达式 not(x) 并无合理的意义。

类型化语言和非类型化语言

变量可以被赋予非平凡的(即非单一通用类型)类型的语言被称为类型化语言。(原文为 typed languages 和 untyped languages,直译为“类型化的语言”和“非类型化的语言”,译者注。)

不限制变量范围的语言被称为非类型化语言:它们没有类型,或者说,有一个包含所有值的单一通用类型。在这些语言中,操作可以应用于不适当的参数:其结果可能是一个固定的错误值或一个异常等。

类型系统是类型化语言的组成部分,它记录变量的类型;一般来说,它也记录程序中所有表达式的类型。类型系统被用来确定程序是否表现良好。只有符合类型系统的程序才应该被认为是类型化语言的真正程序;不符合类型系统的程序应该被丢弃而从不运行。

显式类型与隐式类型

一种语言由于其类型系统的存在而被类型化,无论类型是否实际出现在程序的语法中。如果类型是语法的一部分,该语言就是显式类型的,否则就是隐式类型的。

没有哪种主流语言是纯粹的隐式类型,但是像 ML 和 Haskell 这样的语言支持编写省略类型信息的大型程序片段;这些语言的类型系统会自动为这些程序片段分配类型。

执行错误、安全、行为良好

典型的执行错误有非法指令错误或非法内存引用错误。然而,还有一些更微妙的执行错误,它们会导致数据损坏却不会被立刻感知。此外,有一些通常不会被类型系统预防的软件故障,例如除以 0 和对 NIL 解引用;也有些语言虽然缺乏类型系统,但软件故障却不会发生。因此,我们需要仔细定义我们的术语。

执行错误和安全

区分两类执行错误是很有用的:

  • 第一类是(在许多计算机架构上)会导致计算立即停止的 trapped 错误,例如除以零和访问非法地址。(注:不太好翻译,因此保留了原单词。)
  • 第二类是在发生时没有被注意到而在之后导致程序任意行为的 untrapped 错误,例如在没有运行时边界检查的情况下,访问超过数组末端的(错误)数据。

如果一个程序片段不会导致 untrapped 错误的发生,那么它就是安全的。所有程序片段都是安全的语言被称为安全语言。因此,安全语言排除了那些可能被忽视的最隐蔽的执行错误。非类型化语言可以通过执行运行时检查来实现安全。类型化语言可以通过静态检查来拒绝所有可能不安全的程序来实现安全(但静态检查通常不会特别精确,因此也会拒绝一些安全的程序)。类型化语言也可以使用运行时和静态检查的混合方式。

尽管安全性是程序的一个重要性质,但类型化语言很少只关注和排除 untrapped 错误,即类型化语言通常也致力于排除 trapped 错误。我们接下来讨论这些问题。

执行错误和行为良好

对于任何给定的语言,我们可以挑选执行错误的一个子集作为禁止的错误(也即编译器必须能检查出的错误,译者注)。禁止的错误应该包括所有 untrapped 错误以及 trapped 错误的一个子集。

如果一个程序片段运行时不会发生任何禁止的错误,那么它就是行为良好的。通过简单推论可知,一个行为良好的程序片段总是安全的。

强(类型)检查

一个所有合法程序都有良好行为的语言被称为强(类型)检查的。

因此,对于一个给定的类型系统,以下情况在强检查语言中成立:

  • 没有 untrapped 错误。
  • 被禁止的 trapped 错误不会发生。
  • 其他 trapped 错误可能会发生;避免这些错误是程序员的责任。

类型化语言可以通过执行静态(即编译时)检查来强制保证行为良好(和安全)。这些语言是静态检查的,检查过程被称为类型检查,而执行这种检查的算法被称为类型检查器。一个通过类型检查器的程序被称为类型良好的;否则,它就是类型错误的——但这可能意味着它就是行为不良的,也可能仅仅意味着类型检查器不能保证它是行为良好的。静态检查语言的例子有 ML、Java 和 Pascal(注意,Pascal 有一些不安全的特性)。

非类型化语言可以通过足够详细的运行时检查来排除所有禁止的错误,来强制保证行为良好(和安全)。例如,它们可以检查所有的数组边界和所有的除法操作,当禁止的错误发生时,产生可恢复的异常。这些语言的检查过程被称为动态检查;Lisp 就是这种语言的一个例子。注意,这些语言仍然是强检查的,尽管它们既没有静态检查,也没有类型系统。

即使是静态检查的语言通常也需要在运行时进行测试以达到安全的目的。例如,一般来说,数组的边界必须在动态中进行测试。因此一种语言被静态检查的事实并不一定意味着可以完全盲目地执行。

一些语言利用其静态类型结构来进行复杂的动态测试。例如,Simula67 的 INSPECT,Modula-3 的 TYPECASE,以及 Java 的 instanceof 结构,都是对对象的运行时类型进行区分。这些语言仍然被认为是静态检查的(稍有不妥),部分原因是动态类型测试是在静态类型系统的基础上定义的。也就是说,对类型相等的动态测试与类型检查器在编译时用来确定类型相等的算法是兼容的。

也许安全性是一个更原始的、比行为良好更重要的性质,然而大多数类型系统的设计是为了确保更一般的行为良好性质,以及隐含的安全性。因此,类型系统的目标通常是通过区分类型良好和类型错误的程序来确保所有程序行为良好。

弱(类型)检查

在现实中,某些静态检查的语言并不能确保安全。也就是说,他们所禁止的错误集并不包括所有 untrapped 错误。这些语言可以被委婉地称为弱(类型)检查(或弱类型,在文献中),意味着一些不安全的操作不会被检测出来。这类语言在弱点的表现上差异很大。例如,Pascal 语言只有在使用未标记的变体类型和函数参数时才是不安全的;而 C 语言有许多不安全的、广泛使用的特性,如指针运算和强制类型转换(casting)。有趣的是,C 语言程序员的十条命令中的前五条 [1] 都是为了弥补 C 语言的弱检查方面的问题。C 语言的弱检查所造成的一些问题在 C++ 中得到了缓解,而更多的问题在 Java 中得到了解决,(这或许)证实了脱离弱检查是一种趋势。Modula-3 支持不安全的特性,但只在明确标记为不安全的模块中,并防止安全模块导入不安全的接口。

大多数非类型化语言都是完全安全的(例如 Lisp)。原因也很简单,如果不是这样的话,编程就会变得非常困难和令人沮丧——程序随时可能崩溃,并且难以发现直接原因。例如汇编语言就是一种“令人不快的”无类型的不安全语言。(相信没有人会享受用它去编写大规模的应用程序,译者注。)

对语言和类型系统的若干讨论

语言应该是安全的吗?

实现安全所需的运行时检查有时被认为太昂贵(例如即使在有大量静态分析的语言中,数组越界等检查通常也不能在编译时完全消除),因此出于性能考虑,有些语言被故意做成不安全的,例如 C 语言。尽管如此,仍有许多人在努力设计安全的 C 语言子集,并制作开发工具,试图通过引入各种(相对昂贵的)运行时检查来安全地执行 C 程序。这些努力来自两个主要的原因:

  • C 语言也被广泛使用在那些对性能要求不高的应用中,
  • 不安全的 C 语言程序所带来安全问题,例如缓冲区溢出和算术下溢,可能导致覆盖任意的内存区域,并可被利用进行攻击。

根据不同的衡量标准,安全相对于性能提升或许是更加经济、有效的。

  • 例如安全的程序在执行错误时下会立即停止,这减少了调试的时间。

  • 安全性保证了运行时结构的完整性,因此可以进行垃圾收集,而垃圾收集大大减少了代码的大小和代码的开发时间。(但牺牲了一些性能。)

  • 安全已经成为系统安全的必要基础,特别是对于加载和运行外来代码的系统(如操作系统内核和网络浏览器)。系统安全正在成为程序开发和维护中最昂贵的方面之一,而安全可以降低这种成本。

因此,安全语言和不安全语言之间的选择最终可能与开发和维护时间以及代码执行时间之间的权衡有关。近年来,安全语言有成为主流的趋势。

语言应该类型化吗?

关于编程语言是否应该类型化的问题仍然存在一些争议。毋庸置疑,用无类型的语言编写的代码很难被维护。从可维护性的角度来看,即使是弱检查的不安全语言(例如 C)也要优于安全但非类型化的语言(例如 Lisp)。下面是从工程的角度提出的支持非类型化语言的论据。

  • 程序执行的经济性。一般来说,编译时准确的类型信息使运行时的一些操作无需昂贵的检查。例如类型信息首先被引入到编程中,以提高代码生成和数值计算的运行效率,Fortran 便是一例。例如在 ML 中,准确的类型信息使得指针解引用时无需做 NIL 检查。
  • 小规模开发的经济性。当一个类型系统设计精良时,类型检查可以捕获很大一部分常见的编程错误,从而减少大量的调试时间。因为大量的其他错误已经被排除,这也使我们更容易观测和调试真正发生的错误。此外,有经验的程序员还可以采用特定的编码风格来使一些(隐式的)逻辑错误成为(显式的)类型错误:他们把类型检查器作为一种开发工具。
  • 编译的经济性。类型信息可以被组织成程序模块的接口。然后,模块可以相互独立地进行编译,每个模块只依赖于其他模块的接口。这使得编译大型系统更加高效,因为在接口稳定的情况下,对一个模块的修改不会导致其他模块的重新编译。例如 Modula-2 和 Ada 便是这样。
  • 大规模开发的经济性。接口和模块对代码开发有方法上的优势。大型的程序员团队可以协商要实现的接口,然后分别去实现相应的代码片段。代码片断之间的依赖性被最小化,代码可以被局部地重新安排,而不用担心全局的影响。(这些好处也可以通过非正式的接口规范来实现,但在实践中,类型检查对验证对规范的遵守有很大帮助)。)
  • 安全领域的开发和维护的经济性。正如安全对于消除缓冲区溢出等安全漏洞是必要的,类型化对于消除其他灾难性的安全漏洞也是必要的。这里有一个典型的例子:如果有任何方法(不管多么复杂)可以将一个整数转换成一个指针类型(或对象类型)的值,那么整个系统就会面临风险——攻击者可以在系统中的任何地方访问任何数据。另一个有用的(但不是必须的)技术是将一个给定的类型的指针转换成一个整数,然后再转换成上述不同类型的指针。从维护和整体执行效率的角度来看,消除这些安全问题的最经济有效的方法是采用类型化语言。不过,安全问题在系统的各个层面都是一个问题,因此类型化语言是一个很好的基础但仍不是一个完整的解决方案。
  • 语言特性的经济性。类型结构天然以正交的方式组成。例如,在 Pascal 中,二维数组其实是数组的数组;在 ML 中,有 n 个参数的函数其实是一个具有单个 n-元组参数的函数。因此,类型系统可以促进语言特性间的正交性,让人们思考和质疑(语言中)人为做出的一些限制,从而倾向于降低编程语言的复杂性。

类型系统的预期性质

在本章的其余部分,我们假设语言应该既安全又类型化,因此应该采用类型系统。在对类型系统的研究中,我们并不区分trapped 或 untrapped 错误,也不区分安全和行为良好:我们专注于行为良好,并将安全作为一个隐含的性质。

在编程语言中,类型通常具有实用性特征,这些特征将其与其他种类的程序标注区分开来。一般来说,关于程序行为的标注可以是非正式的注释,也可以是需要经过验证的正式的规格描述。类型位于这个范围中间:它们比注释更精确,比规格描述更容易机械化(自动化)。以下是任何类型系统都被期望具有的基本性质:

  • 类型系统应该是可验证的:应该有一种算法(类型检查算法)可以确保程序的行为良好。类型系统的目的不是简单地说明程序员的意图,而是在执行错误发生之前主动捕捉它们。(任意的形式化规范不具备这些性质。)
  • 类型系统应该是透明的:程序员应该能够轻松地预测一段代码是否可以通过类型检查。如果它不能通过类型检查,那么失败的原因也应当是不言而喻的。(自动定理证明不具备这些特性。)
  • 类型系统应该是强制的:应该尽可能地静态检查关于类型的声明,并动态检查无法静态检查的部分。程序与其类型之间的一致性应该被例行验证。(程序注释不具有这些性质。)

类型系统是如何被形式化的

我们怎样才能保证类型良好的程序是真正行为良好的呢?或者说,我们怎样才能确保语言的类型规则不会意外地放过行为不良的程序呢?

一般的程序语言手册都会或多或少地描述它们的类型系统,而形式化的类型系统是正是那些非正式类型系统的数学特征。一旦一个类型系统被形式化,我们就可以尝试证明一个正确性定理(soundness theorem,似乎一般称为健全性定理),说明类型良好的程序一定也是行为良好的。如果这样的正确性定理成立,我们就说该类型系统是正确的。(即“类型化语言中的所有程序都行为良好”。)

为了使一个类型系统正规化,并证明其正确性定理,我们必须对整个语言进行规范化,正如下文描述的那样。

  • 第一步是描述它的语法。对于大多数语言来说,这可以简化为描述类型和项(terms,一般为语句、表达式和其他程序片段)的语法。类型表达关于程序的静态知识,而项则表达算法行为。

  • 第二步是定义语言的作用域规则,将标识符的每次出现与它们的声明位置(无歧义地)地绑定起来。类型化语言所需的作用域绑定总是静态的,也就是说,所有标识符的绑定必须在运行前唯一确定。绑定关系通常可以纯粹从语言的语法中确定,而不需要任何进一步的分析。静态作用域也被被称为词法作用域(lexical scoping),缺乏静态作用域的情形被称为动态作用域(dynamic scoping)。正式的作用域绑定规则可以通过定义程序片段的自由变量集来给出,之后就可以定义如何去替换类型或项中的自由变量(substitution)。

  • 当这些都解决后,我们可以继续定义语言的类型规则“has-type”。这些规则描述了项 和类型 之间的形式为 的关系(即 有类型 )。一些语言还会定义类型上的形式为 的子类型关系以及形式为 等价关系。语言的类型规则的集合即为它的类型系统,具有类型系统的语言被称为类型化语言。

  • 除此之外,我们还需要引入一个不反映在语言语法中的基本要素——静态类型环境——否则类型规则就不能被形式化,因为类型规则总是针对被类型检查的片段的静态环境而制定。在程序片段的处理过程中,这个静态环境被用来记录自由变量的类型。在类型检查阶段,它与编译器的符号表紧密相关。例如,前文中的类型关系 与静态类型环境 相关联,该环境包含了 中的自由变量的信息。(译者注:例如有 bool 类型的全局变量 x,那么在检查全局函数 int main() { x + 1; } 的函数体时,类型环境 将包含类型关系 ,其中 x 是函数体中的自由变量。)

  • 形式化语言的最后一步是将其语义定义为项和项的计算结果之间的 “has-value” 关系。这种关系的形式在很大程度上取决于所采用的语义风格(例如小步语义,大步语义,译者注)。在任何情况下,语言的语义和类型系统都是相互关联的:项的类型和其计算结果的类型应该是相同的(或有其他适当形式的关联)——这就是正确性定理的本质。

类型系统的基本概念几乎适用于所有编程范式(函数式、命令式、并发式等等);对于不同的范式,一些类型规则往往可以不加改变地使用。例如,无论编程范式是命令式还是函数式,无论语义是按名调用(call-by-name)还是按值调用(call-by-value),函数的基本类型规则都是一样的。

关于类型等价:如上所述,大多数非平凡的类型系统需要定义一个类型上的等价关系。这是定义编程语言时的一个重要问题:什么时候独立给出的类型表达式是等价的?例如,

1
2
type X = Bool
type Y = Bool

如果上述类型名 X 和 Y 由于相等,我们就有了结构等价。如果它们不相等,我们就有按名等价

在实践中,大多数语言都既使用了结构等价又使用了按名等价。单纯的结构等价可以通过类型规则轻松而精确地定义,而按名等价则更难确定,而且往往有一种算法的味道。当类型化的数据需要在网络上存储或传输时,结构等价具有独特的优势;相比之下,按名等价不容易处理那些在时间或空间上分别开发和编译的交互程序。

在本章中,我们讨论了独立于语义的类型系统。不过,我们应该知道,最终一个类型系统必须与语义相关,而且正确性理论应该对该语义成立。

用以描述类型系统的语言

类型系统指定了编程语言的类型规则,但它又独立于特定的类型检查算法;正如形式化的语法可以描述编程语言的语法,但它又独立于特定的语义解析算法。

将类型系统与类型检查算法脱钩既方便又有用:类型系统属于语言定义,而特定算法则属于编译器。用类型系统来解释语言的类型方面——相比于用某个编译器所使用的算法来解释——总是较为容易的。此外,不同的编译器可能对同一个类型系统使用不同的类型检查算法。(作为一个小问题,从技术上讲,可以定出只存在实际不可行的类型检查算法或者根本就不存在类型检查算法的类型系统;然而,通常的意图是允许有效的类型检查算法。)

断言

对一个类型系统的描述始于对断言(judgements)的形式化描述。一个典型的断言形式如下(其中 意为蕴含(英文为 entails):

这里 是一个静态类型环境;例如,它可以是一个由(不同)变量及其类型组成的有序列表 。空环境用 表示, 中声明的变量 的集合用 表示,它即为 的定义域。 的形式因断言而异,其中的所有自由变量都必须在 中声明。

就我们目前的目的而言,最重要的断言是关于类型关系的断言,它表明一个项 在静态类型环境下具有类型

示例:

其他的断言形式往往也是必要的。一个常见的断言形式是指明一个环境是构造良好的(well-formed):

任何给定的判断都可以被看作是有效的(如 )或无效的(如 )。有效性形式化地描述了类型良好这一的概念。有效断言和无效断言之间的区别可以用多种方式表达,但这种描述合法断言的方式已经成为主流。此外,类型规则是高度模块化的:不同语言要素的规则可以单独编写(这与单一、巨大、复杂的类型检查算法相反)。因此,类型规则相对来说更容易阅读和理解。

类型规则

类型规则在其他已知的有效的断言的基础上说明某一断言的有效性。这个过程通常由一些本质上一定有效的判断(通常是 ,它表示空环境是构造良好的)开始。

每条类型规则都写成横线之上的若干前提判断 ,横线之下是单一的结论判断。当所有的前提得到满足时(前提的数量可以是零),结论必须成立。每条规则都有一个名称。(按照惯例,名称的第一个字由结论中的断言决定;例如,”(Val …) “形式的规则名称是指其结论为关于值(即项的计算结果,译者注)的类型断言的规则。) 当需要时,限制规则适用性的条件,以及规则中使用的缩写,都会在规则名称或前提旁边加以注释。

例如,下面两条规则中的第一条指出,在任何结构良好的环境 中,任何数字都是一个 类型的表达式。第二条规则指出,表示自然数的两个表达式 可以组合成一个更大的表达式 ,它也表示自然数。此外, 的环境 声明了 中的所有自由变量的类型,并且也对 有效。

类型规则二例

类型规则的集合被称为(形式化的)类型系统。从技术上讲,类型系统符合形式化证明系统的一般框架:用于进行逐步演绎的规则的集合。在类型系统中进行的演绎关注程序的类型化。

类型的推导

在一个给定的类型系统中,一个推导过程(derivation)是一棵断言树,上面是叶子,下面是根,其中每个断言都是通过系统的一些规则由紧挨着它的断言得到的。对类型系统的一个基本要求是,必须能够检查一个推导是否被正确地构造。

在一个给定的类型系统中,一个有效的断言是通过正确地使用类型规则得到的,因此它一定是作为某个推导的根得到的断言。例如,使用前面给出的三条规则,我们可以建立下面的推导,从而确定 是一个有效的判断。每一步应用的规则都显示在每个结论的右边。

类型推导一例

类型良好和类型推断

在一个给定的类型系统中,如果在环境 下,存在一个类型 ,使得 是一个有效的断言,那么项 就是类型良好的。

探索一个项的推导过程(也就是类型)被称为类型推断问题(type inference problem)。在上述简单类型系统中,可以在空环境下为项 推断出一个类型。通过前面的推导,这个类型是

假设我们现在添加一个类型规则,其前提为 ,结论为 。在该类型系统中,因为不存在自然数与布尔数相加的规则,所以我们无法推断出项 的任何类型。由于 没有任何推导过程,我们说 是不可类型化的,或者说它是类型错误的,或者说类型化过程有错。

我们可以进一步增加一个类型规则,其前提是 ,结论是 (例如,意图是将 解释为)。在这样一个类型系统中,可以为术语 推断出一个类型,它是类型良好的。

因此,一个给定项的类型推断问题对有关的类型系统非常敏感。根据类型系统的不同,类型推断的算法可能非常容易,也可能非常困难,甚至不可能找到。如果找到了,最好的算法可能是非常有效的,也可能是慢得无可救药的。尽管类型系统被表达出来,并且经常被抽象地设计出来,但它们的实际效用取决于是否有好的类型推断算法。

像 Pascal 这样的显式类型的程序性语言的类型推断问题是相当容易解决的,隐式类型语言如 ML 的类型推断问题要微妙得多:而在多态(polymorphism)存在的情况下,类型推断问题变得特别困难。Ada 和 Standard ML 的显式类型多态结构的类型推断问题在实践中是可以处理的;然而,这些问题基本上是由算法解决的,而没有描述它们的类型系统。适用于多态的最纯粹和一般的类型系统是由 λ-演算给出的(之后介绍)。

类型正确

现在我们已经建立了所有关于类型系统的一般概念,可以开始研究特定的类型系统了。之后我们会回顾一些非常强大但又比较理论化的类型系统:我们首先了解这些特定的类型系统,这样就可以更容易地为编程语言中可能遇到的各种复杂的特性编写类型规则。

当我们沉浸在类型规则中时,我们应该记住,一个合理的类型系统不仅仅是一个任意的规则集合。类型良好是为了对应于行为良好这一语义概念。人们习惯于通过证明类型正确性定理来检查类型系统的内部一致性,这就是类型系统与语义交汇的地方。对于指称语义(denotational semantics),我们期望如果 是有效的,那么 就成立( 的值属于类型 所表示的值的集合)。对于操作语义,我们期望如果 以及 归约(reduce,可以简单理解为计算,译者注)为 ,那么 也成立。在这两种情况下,类型正确性定理都断言了类型良好的程序在计算时不会出现执行错误(这里忽略证明)。

在本系列的下一篇文章中,我们会介绍一些主流编程语言中常见的类型系统和其中的类型规则。


微信公众号 编程语言Lab 上也有:
https://mp.weixin.qq.com/s/GJsR_P7xS9h2pP4z8mjvcg


MathJax 渲染有点奇怪,最终本文内的所有 \mathit{Nat} 都改为了 Nat

2023 年留言:别看了,亏麻了。

2021 年 9 月 5 日

继上次写的“投资指南——新韭篇”后,又过去了 4 个月。这四个月中我的运气还挺好的,白酒、医药、芯片、5G、新能源车、光伏、军工的便宜我都捡到了……但又因为不敢梭哈,所以这四个月间基金的总收益大概增长了 12%。当初说好的定投宽基呢

首先,我等新韭不能高估了自己心态。因此本文先谈谈心态这事儿,之后说既然这种心态不可避免,如何投资会更稳妥些。

我们的心态没自己想象的那么好

下跌时

大家在买基金或者股票开户前,应该都做过“风险承受能力”问卷。问卷中往往会有些题目问我们

  • 投资期限,以及
  • 能承受本金多大幅度的亏损。

我猜很多人或许跟我一样,填了“投资期限2年+”以及“可以承受本金20~50%的亏损”(甚至 50% 以上的亏损)。现在回想起来,大概只是个笑话。回想一下:

  • 1 天跌超过 5% 是什么感觉?
  • 连续跌 7 天是什么感觉?
  • 1 个月跌 30% 是什么感觉?
  • 半年甚至一年不回本是什么感觉?

发生上述情形时,如果想撤资,那就是承受不住呀——特别是我们觉得投资方向和方式没有错的时候。毕竟,对新人来说,2 年以上的投资和忍受浮亏 50% 谈何容易。

上涨时

另一方面,在上涨时:

  • 1 天涨超过 5% 是什么感觉?
  • 连续涨 7 天是什么感觉?
  • 1 个月涨 30% 是什么感觉?

这时候有想过撤资吗?其实这时候撤资无非就是想赚更多:觉得涨得过分了会跌回去,先卖出等跌回去了再买。

应对策略

本文不是鸡汤文,所以也不会谈所谓的“改善心态”。本文要谈的是“如何系统性地控制回撤(即浮亏)”。

方法一:选择一只收益率平滑的老牌基金

下图是美国的桥水全天候基金与标普 500 被动基金的收益对比。

桥水全天候基金与标普 500

第一眼看去,1991~2015 年间桥水全天候基金并没有比单一标普 500 被动基金多出任何收益(这既是很多投资理财书籍的观点,也是我几个月前所持的观点)。但仔细看图,我们还可以发现桥水全天候基金的曲线比标普 500 平滑得多。对个人投资者来说,这通常意味着

  • 股市大跌时没那么难以忍受和想卖出,
  • 股市大涨时没那么难以忍受和想卖出;
  • 任何时候大额买卖都是相对安全的。

这其实对还没入场的(小富即安的)新人是非常友好的。

这里举的是美股的例子,而且这个基金我们一般人不好买到。在癌股里,怕麻烦的可以直接选债基基金,这种基金平均年化一般在 6%~12%,收益越低波动越低,收益越高波动越高。这种基金其实挺多的,这里就不做推荐了。(但考虑到资金流动性,我觉得还是 6 个月内可 0 费率赎回的比较好。)

方法二:用纯债和股票组合出自己的债基基金

不怕麻烦的可以自己按比例选择一些纯债和股票基金。

虽然与法一相比麻烦了许多,但也有组合更加灵活、选择更加宽泛的优势:

  • 纯债可以随时投入。
  • 股票型基金可按自己喜好选择。

方法三:题材、大小盘对冲

我们还可以考虑一些不同涨同跌的股票型基金来平滑收益率曲线。

  • 比如新能源和基建房地产就有点对冲的味道。(260112 有点意思(但也只是有点意思。)。)
  • 上证主板科创创业版是不是也有点对冲的味道。
  • 大盘蓝筹(如上证 50,上证 100,沪深 300)和中小盘成长(中证 500,中证 1000)是不是也有点对冲的味道。再比如中美是不是也有点对冲的味道?。

涨了几年的大盘蓝筹最近几个月是不涨反跌,但最近 3 个月中证 500 涨了 20% 了吧,目前点位处于 2015 年股灾时的 25% 位置。创业板那就涨得更多了。

方法四:长短线对冲

“你是左侧买入还是右侧买入?”

  • 左侧买入是指在下跌趋势时觉得超跌了,去抄底,提前布局。但一般是抄在山腰上,还会继续下跌。所以这种方式一般赚的是半年一年甚至两年后的钱,比较长线;因此左侧买入一般也可以叫价值投资。新手切记第一次抄底不要梭哈。
  • 右侧买入时指在上升趋势时买入,稍微赚一笔,小富即安。这种要注意不能太贪,根据买入时机和题材,一般上涨 10%~15% 时就是个会回调的小高点了。同样,历史高点时不建议梭哈。(本人通过这种方式在今年的热点题材上赚了不少。)在癌股,热点题材还是要追的吧,送上门的钱为什么不要?

其实就是那句话吧:不要和趋势作对,在上升期中赚钱是容易的,在下降期中赚钱是困难的;所以我认为追涨杀跌也不无道理。这种长短线对冲,往往能淡化一些长线布局带来的临时损失。

另外,我个人的理念是尽量不在左侧买入。价值投资也是在横盘处买入。

方法五:全球视野

分散一些资金到香港、美国市场。根据自己喜好选择制造业或者互联网,不过一般互联网居多。

  • 大家听到烂的纳斯达克 100 指数、标普 500 指数。
  • 恒生指数、恒生互联网指数。
  • 中概互联网指数。

注 1:最近中概互联网是真的低,在我上次抄底(失败)后又跌了 30%,近乎腰斩。

注 2:喜欢玩的还可以看看美国基建房地产呀,美国 REIT 还没恢复到疫情前水平。

注 3:玩美股新手就不要想着低买高卖了,定投就好了,反正一直涨,除非国际形势出幺蛾子跌了 20% 什么的。

方法六:买 “N 年定开”或 “N 年持有”

有一小撮基金是不能随意买卖的,一般有“N 年定开”和“N 年持有”的标注。

  • N 年定开是说每 N 年后,在固定期限内开放买卖。
  • N 年持有是说每次买入后的份额,持有 N 年后才能卖出。

管不住自己手的可以买这种基金,然后把软件删了就行:反正涨了卖不掉,跌了甚至也买不了,就当不存在吧。

但缺点也显而易见:流动性大为降低。不过也有不到一年的,可以考虑一下。

另外,喜欢补仓的请买 N 年持有而不是 N 年定开。记性不好的也得买 N 年持有。N 年定开到时候忘了卖也不是闹着玩的。

(我算是交足了学费,买了个 N 年定开的目前亏损 20% 多还不能补仓。)

个人对未来癌股的看法

个人感觉癌股市场挺像政策市场的。国家规划要发展啥就要发展啥,甚至有点其他赛道的都不许涨的味道。这一点从最近的央视新闻也能看到:教育、游戏、白酒样样被锤。

  • 过去五年涨了大盘蓝筹(和白酒)。
  • 未来五年应该是科技。至少未来两年科创板创业板肯定是主航道:新能源车、光伏、芯片、医疗。未来大概属于科技和高端制造业。
  • 癌股开放了外资基金,以后资金量应该会更大。(近期贝莱德就搞了个 80 亿的基金,让我们看看水土服不服,是不是也要被割哈哈哈。)

这半年,反正我定投的大盘蓝筹这半年没赚到一分钱,反而赔了几个点。低吗?比炒上天的热门赛道低多了,个个近乎腰斩,但就是不赚钱。

近期出现了主板创业板轮动的局面,比如主板涨几天跌几天,科创创业板涨几天跌几天;板内甚至出现题材快速轮动的局面。这时候追涨杀跌就是作死。但是多面埋伏,逢高卖出就赚翻了。

  • 白酒:近期有企稳的现象,喜欢抄底的朋友们可以买一点。
  • 医药:不稳,轮动下跌,观望为主。感觉资金在流出。
  • 军工:一个月涨了 30% 又跌了 10%,感觉资金在流出。
  • 芯片:一个月涨了 30% 又跌了 10%,感觉资金在流出。但这些企业的估值吧,一言难尽。(而且国家大基金早就撤资了。)
  • 光伏:资金进进出出,最近好像又在进。这是 toB 市场,年增速 20% 稳的。但这些企业的估值吧,一言难尽。
  • 新能源:资金进进出出。这是 toC 市场,可能有爆炸增长,但这些企业的估值吧,一言难尽。

总结

新人心态容易爆炸,请做好风险对冲:

  • 怕麻烦就选债基打底的基金。
  • 不梭哈在同一个股票型基金
  • 不梭哈在同一个国家的市场。
  • 大小盘结合:大盘蓝筹、中小盘成长要有配比。
  • 长短线结合:既要使用定投赚一两年后的钱,也要赚当下的钱。
  • 题材结合:热点题材多布局,轮动的时候逢高卖出。
  • 交易时机:短线趋势“追涨杀跌”,长线“追跌杀涨”,轮动和震荡“追跌杀涨”。
  • 实在不行买 N 年持有,然后删软件。

另外,最近红利低波开始涨了;还有,B 圈不也可以图个乐子考虑一下吗?

附录 II:明灯(冥灯)

冥灯自然不构成投资建议。

债基、债券

  • 000037
  • 003547
  • 001868

宽基指数(沪深 300 太多,自己找)

  • 中证 500 502000,001557
  • 中证 1000 013331
  • 中证 100 010351
  • 科创创业 012895
  • 纳斯达克 040046
  • 标普 161125
  • 美国 REIT 160140

定投且稳定亏损中(你们博士真的不行啊)

  • 富国天惠 003494
  • 华商红利 000279

其他

  • 房地产 519191
  • 白酒 012414
  • 军工 011148
  • 动漫游戏 012769
  • 化工 012538
  • 养猪 012725
  • 能源基建 260112
  • 新能源替代品 001532
  • 中概互联网 006328
  • 012608
  • 医疗 010685
  • 芯片 008888
  • 随便玩玩 003567,004235,161031,003305,012771,001605

附录 I:近期时间加权收益率

对比上证指数:

对比上证指数

对比沪深 300:

对比沪深 300

对比 中证 500:

对比中证 500

对比创业板:

对比创业板

垃圾软件没提供资产加权收益率。

0%