An odyssey to real world 现实世界的奥德赛

一个月前, 我决定远离互联网上那些精心准备的内容, 让每日听到的和看到的东西都尽量贴近现实, 进行一次回归现实的奥德赛.

为什么要清理信息来源

在这个影像+移动互联网时代, 尽管在我刻意控制的情况下, 我每天用在手机上的时间也在3-4个小时, 看的大多数是youtube, 推特等APP里精心准备的各种内容, 例如影视拉片, 经济分析, 体育集锦, 自媒体等等.

这些APP推送和组织信息目的就是一个: 想办法吸引我们的注意力, 让我们留在APP里, 留的时间越长越好.

这些APP主要通过两种方式在我们大脑中形成成瘾神经回路, 让我们停不下来, 像个赌鬼或者瘾君子:

  1. 下拉刷新的更新方式, 类似于赌场老虎机, 以一定概率刷出你喜欢的内容, 但并不100%推送你喜欢的内容, 同时根据你的点击或者划过的动作, 快速适应你的新喜好.

    这样你就会像赌博一样, 不停地下拉刷新, 不停地抽奖, 成瘾效果非常好.

  2. APP里的内容, 以秒为单位, 不停地在挑起我们的情绪, 刺激我们的大脑, 让大脑持续处于多巴胺爆棚状态.

    Stanford 的神经科学家 Andrew Huberman, 在一次采访里说过:

    任何导致多巴胺快速重复波动的行为或者物质都会在神经系统中形成一种模式, 你会渴望那种东西, 而且随着时间的推移, 它会给你越来越低的满足感.

    所以我们会越刷越觉得不过瘾

与此同时, 我接收的这些信息给我营造了一个完美世界的幻觉, 看多了这种与现实世界不匹配的内容, 会提高我对现实的期待, 扭曲了我对现实世界的认识.

Andrew 也给出了解决方案: 重置成瘾脑回路的唯一方法就是停止, 然后在它的位置上做其他的事情, 理想情况下, 做大脑适应性的事情.

所以远离虚假信息的办法就是:停止, 用高质量真实的内容替换它们, 创造更多接触现实世界的机会.

清理什么内容

我尝试清理我接收到的任何会导致大脑里的多巴胺快速重复波动的内容.

我现在仍然会看视频节目或者听podcast, 但是我目前仅仅局限于看以下的内容:

  1. Jordan Peterson 的采访和讲课视频 (心理学教授, 出过两本书《12 Rules for Life》, 《Beyond Order: 12 More Rules For Life》)
  2. Andrew Huberman 的采访和podcast (Stanford 神经科学家)
  3. Naval Ravikant 的采访(硅谷投资人), 特别推荐Chris Williamson采访他的这一期 44 Harsh Truths About Human Nature,《纳瓦尔宝典》这本书也不错

这些内容我认为足够真实, 是来自现实世界的信息, 增强了我对现实世界的认识, 而且每集都在1小时以上, 量大管饱, 足够看半年以上了.

Shangri-La of CPP - Template Metaprogramming(TMP)

C++程序员生活在两个世界里, 区别在于是否使用template metaprogramming(TMP).

C++ programmers live in two worlds, which are different depending on whether they use template metaprogramming(TMP) or not.

一个世界是几乎不使用TMP, 另一个世界几乎用TMP完成95%的代码.

In one world, programmers almost never use TMP. In the other world, programmers use TMP for about 95% of their code.

这篇文章是写给第一个世界C++程序员的TMP使用技术简介.

This article is a short introduction to TMP for C++ programmers in the first world (who do not use TMP often).

我们先使用TMP实现一个简单的程序, 你可以思考下如果不使用TMP应该如何实现.

Let’s start with a simple example using TMP. You can think about how you would write it without TMP.

The Illusion of a Perfect World 完美世界的幻觉(2) - 学游泳,你学会才下水?

上一篇完美世界的幻觉, 有几个点我打算单独拿出来聊一聊.

这篇文章我想讨论的是完美主义(Perfectionism).

在合适的事情上, 适度的完美主义, 有助于我们追求卓越, 是好的.

但是, 过度的完美主义是有害的, 而且完美主义越严重, 影响越大, 下边是我总结的从轻到重的影响

1. 过度精益求精, 浪费了时间

大多数事情做到80%的水平, 只需要20%的时间, 越追求更高的水平, 所需的时间是指数级别增长的.

而且80%的事情做到80%的水平往往是足够的, 必须有智慧去选择那10-20%的事情去追求更高的水平. 不然就会在无意义的事情上浪费大量的时间和精力.

比如孔乙己追求掌握回字的四种写法, 不同的人可能会在不同的事情上去研究回字的四种写法, 成为另一个孔乙己.

2. 阻碍我们行动

过度的完美主义会导致我们想要制定一个完美的计划, 等待一个完美的时间, 做好充足的准备,

总是觉得还差点什么, 总觉得还有些原理还没搞明白, 门道还没看清楚, 总想要再等等.

3. 想像和现实脱节, 导致自我贬低

过度完美主义, 会在脑子里预想整个事情发展的完美过程, 但是当落地到现实中就会被现实教育:

本来以为重要的地方并不重要, 本来以为做好了planB, 发现planB并没有用, 等等.

当想像和现实冲突严重的时候, 过度的完美主义容易走向两个方向:

  1. 要求现实符合想象
  2. 自我惩罚觉得计划的不够好, 进一步进入自我贬低.

而这两个方向都不能带领我们前进, 对于事情的推进没有任何帮助.

该如何防止过度完美主义

脑子里的想法是无法改变现实世界的, 只有行动才能带来改变.

解决之道都很简单, 但只有不断地实践才能真正的改变我们的生活.

  1. 对于容易过度优化的人来说, 可以大概给自己做的事提前定个质量标准时间标准, 在规定的时间内, 按质量完成, 时间到没完成, 要么降低质量标准,要么延长时间.

    比如: A任务要达到70%的质量, 在3小时内完成, B任务要达到90%的质量, 5天内完成.

The Illusion of a Perfect World 完美世界的幻觉

今天和我的心理咨询师聊到了一个现象, 我觉得很有启发:

我们的意识被悄悄植入了一个存在完美世界, 完美超人的幻觉. 而这个观念在我们的思想里塑造了一个完美全能的形象, 可以游刃有余的解决掉任何棘手的问题.

有的信息是在塑造一些超人形象, 这些形象总是能够力挽狂澜, 再困难的问题到了他们这里, 他们都会在谈笑间轻轻松松化解了, 比如:

  1. 黄飞鸿总是能轻轻松松战胜对手
  2. 诸葛亮总是摇摇扇子就把敌人打败了
  3. 张飞更是隔岸喊一嗓子就把敌人吓退了
  4. 自由搏击KO集锦, 都是一名选手轻松一脚KO, 对方就像落叶一样倒下了
  5. 10大经典进球, 都是前锋轻轻松松各种花式过人, 最后轻松破门, 留下门将一脸茫然
  6. 还有更多漫威里的形象更是如此

有的信息是在塑造一些完美世界, 仿佛这个世界上就是有人的生活就是各种顺利, 各种胜利, 各种拿到最后想要的结果, 一直都在巅峰体验, 比如:

  1. 小红书, 抖音里各种"精致"生活, 那些博主好像要不就是生活在完美世界, 各种顺利, 要不就是个人能力超强, 不费吹灰之力就把生活里里外外搞得牌亮条顺, 让大家一阵羡慕
  2. 很多影视作品里也是这样, 主角各种计划都不做, 全凭临场反应, 在头脑和体力上各种碾压对手, 打的敌人毫无招架之力, 哪怕在危急时刻, 也不耽误主角装X喝口酒慢悠悠起来继续赢到最后
  3. 甚至连记录片都有二次加工的过程, 刻意突出一些, 刻意隐藏一些.

然而这些都不是真正的生活. 他们要么是对生活最精彩的部分的提炼, 要么就是刻意美化, 很多甚至根本就是假的, 是幻想出来的完美世界, 完美人类.

我们吃的东西塑造了我们的身体, 我们接收到的信息塑造了我们的思想.

所以当我们潜意识接纳了这些虚假的原型, 以这个想象中的完美形象为标杆, 去评价自己当下的生活, 就会觉得挫败和气馁, 甚至会阻碍我们去行动.

当我们吃了太多垃圾食品, 搞坏了身体, 我们就会感受到, 修复的方法可以是: 吃健康的食物, 合理的作息, 适度的运动, 经过几个月或者几年时间或许能调整过来.

但处理垃圾信息对我们的影响, 却不像拒接垃圾食物那么容易.

Pirate's kiss (1) - probability

1

Note: The main content is first written in Chinese, with the English translation following below.

Chinese Version

我打算写一系列的文章来记录我是如何在生活中应用 Pirate's kiss 这个理论的. 内容会涉及概率论, Gambling, 扑克, 交易, 投资等等.

什么是 Pirate’s kiss?

这个词要分开理解.

首先我们先理解kiss, 这里指KISS原则, 在英语里是Keep It Simple, Stupid, 当然我倾向于KISS = Keep It Stupid Simple.

KISS原则类似于奥卡姆剃刀, 就是尽量用简单的方式解决问题, 不仅仅是不要over kill, 而是要尽量的简单, Stupid Simple的那种简单.

然后是Pirate, 在这里指海盗精神, 就是不随大流, 不墨守成规, 有自己的思想, 知行合一, 在一些关键问题上, 不会轻易接受主流认知, 总是先质疑, 然后验证, 最后才是决定是否接受.

比如:

  1. 金融市场是有效的, 价格是当前所有信息综合起来的表现, 不存在套利机会
  2. 在二级市场里个人是无法战胜机构, 基金经理无法战胜指数
  3. 只要在X时候买入A股票长期看来能盈利
  4. 只要找到X指标, 交易就能盈利
  5. 有钱人都坏, 我变坏了也能赚到钱

所以Pirate's kiss原则就是, 当看到上述这些论点时:

Think Programming(2) - OO VS FP

Note: The main content is first written in Chinese, with the English translation following below.

Chinese Version

OO VS FP

接下来我想讨论一下 OO 和 FP. 先说结论:

只使用任何一个都不能写出能快速交付, 同时又容易维护的代码工程.

我们需要结合这两种编程模式的优点, 谨慎使用这些思想工具, 尤其是OO, 如果过度使用OO的一些编程思想, 例如: 继承, 代码会很快变得难以理解和维护.

未完待续…

English version

OO VS FP

Now I want to talk briefly about Object-Oriented (OO) and Functional Programming (FP). My conclusion is:

using either approach alone won’t help you write code that’s both quick to deliver and easy to maintain.

Think Programming(1) - Insights from My Coding Journey

Note: The main content is first written in Chinese, with the English translation following below.

Chinese Version

我编写商业软件到现在有10年的时间.

使用过的编程语言(按掌握程度排序): C/C++, Python, Python(machine learn), F#, Golang, Scala, Clojure, JavaScript

使用过的编程范式: Object-Oriented (OO), Functional Programming (FP)

实现过的软件项目: 低延迟TCP/UDP Server side Framework, 高并发订单系统, 利用machine learning实现的高性能预测系统等等

我计划在这篇文章里记录一下我对编程的一些思考, 而且这些想法随着我解决更复杂问题, 积累更多的经验后也会有些变化, 因此我会不断更新这篇文章.

自顶向下编程

有两种编程理念, 一种是自底向上, 一种是自顶向下.

自低向上: 先实现很多小的函数, 然后使用这些小函数组成很复杂的功能. 在很多讲lisp的书里, 经常会讲如何实践自底向上的编程思想.

自顶向下: 从使用者的角度, 先写完框架/函数API, 最后才是具体代码实现.

我赞同使用很多小的函数组成很复杂的功能这个编程思路, 但是在我的编程实践里, 我认为自顶向下才更容易写出高质量的代码.

举个例子: 假如我们要写一个网站,用来展示在不同的网站上,同一款汽车的最新销售信息, 方便用户选择最优的网站去购买汽车

如果使用自底向上的思路, 我们会依次实现这些代码

  1. 设计数据结构
  2. 去不同网站拉取数据的的代码
  3. 实现数据CRUD的代码
  4. 实现前端与后端数据交互的api
  5. 前端代码

但是如果使用自顶向下的思路, 我们会先写/画出框架, 然后依据框架给出API, 并不需要立刻实现具体代码逻辑.

Advent of Code 2024 Day13

For every input, there is only one or zero solution, so that is not a coding question, it checks if you know basic math. :D

type Day13(lines: string[]) =
    let lines =
        String.Join("", lines)
        |> split2Int64ByReg @"(\d+)"
        |> Array.concat
        |> fun nums -> nums |> Array.splitInto (nums.Length / 6)

    let getMinCost (ai, aj) (bi, bj) (ti, tj) =
        // a * ai + b * bi = ti
        // a * aj + b * bj = tj
        // solve a, b
        // because for every a, b, t only have one or zero int solution
        let d = ai * bj - aj * bi
        let a = (ti * bj - tj * bi) / d
        let b = (tj * ai - ti * aj) / d

        if a * ai + b * bi = ti && a * aj + b * bj = tj then
            Some(a * 3L + b)
        else
            None

    member this.Q1() =
        lines
        |> Array.toList
        |> List.choose (fun nums -> getMinCost (nums[0], nums[1]) (nums[2], nums[3]) (nums[4], nums[5]))
        |> List.sum

    member this.Q2() =
        lines
        |> Array.toList
        |> List.choose (fun nums ->
            getMinCost (nums[0], nums[1]) (nums[2], nums[3]) (10000000000000L + nums[4], 10000000000000L + nums[5]))
        |> List.sum

You can find the source code at https://github.com/zangruizhe/AoC

Advent of Code 2024 Day9

AoC 2024 Day9 F# solution #AdventOfCode #fsharp

Today, my solution takes 5 seconds to get the result, which means my algorithm is not good enough because AoC questions usually only take 1 second to get the result.

let me know if you have some good ideas. :D

type Day9(lines: string[]) =
    member this.Q1() =
        let transform (l: string) =
            l
            |> Seq.mapi (fun i c ->
                let n = char2Int c

                if i % 2 = 0 then
                    Array.init n (fun _ -> $"{i / 2}")
                else
                    Array.init n (fun _ -> "."))
            |> Seq.concat
            |> Seq.toArray

        let lines = String.Join("", lines) |> transform

        let rec shift i j =
            if i < j then
                match lines[i] = ".", lines[j] <> "." with
                | true, true ->
                    lines[i] <- lines[j]
                    lines[j] <- "."
                    shift (i + 1) (j - 1)
                | true, false -> shift i (j - 1)
                | false, true -> shift (i + 1) j
                | false, false -> shift (i + 1) (j - 1)

        shift 0 (lines.Length - 1)

        lines
        |> Array.mapi (fun i c -> if c <> "." then int64 i * (int64 c) else 0L)
        |> Array.sum

    member this.Q2() =
        let transform (l: string) =
            l
            |> Seq.mapi (fun i c ->
                let n = char2Int c

                if i % 2 = 0 then
                    Array.init n (fun idx -> (idx + 1, $"{i / 2}"))
                else
                    Array.init n (fun idx -> (n - idx, ".")))
            |> Seq.concat
            |> Seq.toArray

        let lines = String.Join("", lines) |> transform

        let rec shift i j =
            let ni, ci = lines[i]
            let nj, cj = lines[j]

            if i < j then
                match ci = ".", cj <> ".", ni >= nj with
                | true, true, true ->
                    for n in 0 .. nj - 1 do
                        lines[i + nj - n - 1] <- lines[j - n]
                        lines[j - n] <- (fst lines[j - n], ".")

                    shift 0 (j - nj)
                | true, true, false -> shift (i + ni) j
                | false, true, _ -> shift (i + 1) j
                | true, false, _ -> shift i (j - 1)
                | false, false, _ -> shift (i + 1) (j - 1)
            elif cj <> "." && j - nj > 0 then
                shift 0 (j - nj)

        shift 0 (lines.Length - 1)

        lines
        |> Array.mapi (fun i (_, c) -> if c <> "." then int64 i * (int64 c) else 0L)
        |> Array.sum

You can find the source code at https://github.com/zangruizhe/AoC