[Elixir Macro #5] 变量不变

写这篇文章的想法,源自一次关于 and 和 && 区别的讨论。这次开门见山把结论放出来:Elixir 本质上变量是不可变的

下面开始复现之前的讨论,慢慢解释。同样需要一些知识准备,一个文档两个项目:Reconstructing source code Macro Expansion Sequential Binding

iex(1)> a = 1
1
iex(2)> true and (a = 2)
2
iex(3)> a
nil
iex(4)> b = 1
1
iex(5)> true && (b = 2)
2
iex(6)> b
2

Read more »

[Elixir Macro #2]编译时和运行时

首先,先确定下本文中的这两个概念:

编译时:从 mix compile 命令开始到该命令结束,是解释源码,编译过程生成 beam 文件的过程

运行时:VM 运行 beam 中间代码的过程,和源码文件无关

在自己写代码或读别人代码的时候,弄明白一个变量或一个函数是编译时起作用的还是运行时起作用的,非常重要。 Read more »

[Elixir Macro #1]准备工作:defmacro

首先简化问题,先讨论无参数的 defmacro。

defmacro 最常见的用法,看长像是下面这样的:

defmacro m do
  quote do
    IO.puts "m"
  end
end

最初学 macro 的时候,给我第一印象就是:defmacro 和 quote 是绑定的。

很显然,这是首先要纠正的东西,因为 defmacro 要求的输出是 AST,只不过恰好 quote 是用的比较多的生成 AST 的方法而已。

生成 AST 的方法还有很多,比如: Read more »

[Elixir Macro #0] 开始

最近发现 Elixir 的宏是个争议很大的东西,有人觉得太复杂没啥用;有人觉得是神器;还有人一直说学不知道干啥的,学不进去。所以想到写这一系列的文章,描述一下我所理解的宏。

其实里面大部分的内容,在之前的一次 meetup 里面提到过,但是当时留下 PPT 之类的资料,这里也算是一个总结。

在此之前,需要有相应的知识准备,官方文档关于宏的介绍:Quote and unquote 和 Macros

以下是目前已经想到的主题,随时更新:

  1. [Elixir Macro #1]准备工作:defmacro
  2. [Elixir Macro #2]编译时和运行时
  3. [Elixir Macro #3]实例分析:plug router
  4. [Elixir Macro #4]实例分析:plug builder
  5. [Elixir Macro #5] 变量不变

[Elixir ORM #2] `~>` 和 `<~` 的实现

首先列一下需求吧:

  1. C/S 模式,需要在当前 node 调用,同时需要在其它 node 通过 :rpc.call 调用
  2. 在服务端定义的 User 等 module 对应的表,不需要在每个 client 重新定义
  3. 不希望占用 where order insert update 等常用函数
  4. 不喜欢 LINQ

所以使用 ~>  和<~  只是因为我实再找不到其它的办法能满足上面的需求。

实现过程中,第一步肯定是调研。我先测试了一下 quote do: User ~> where(id: 1) ,结果是{:~>, [], [{:__aliases__, [alias: false], [:User]}, {:where, [], [[id: 1]]}]}这说明现 ~> 的优先级还是比较高的,有足够的发挥空间,这么实现是可行的。 Read more »

HEX.PM 配置

UPYUN 已提供 HEX 的镜像,本帖中的源即将停用。请使用 https://hexpm.upyun.com

已经有官方版的教程了,戳 这里

Read more »

[Elixir ORM #1] Repo & Model 的 DSL 设计

Ench Repo 逻辑相当简单,只是读配置,用 pooler 起一个池,再给自己定义个 &__using__/1 让 Model 可以 use 它就好了。

和 Ecto 最大的区别,把 Repo 和 Model 做了绑定,一个 Model 只属于一个 Repo,所以调用的时候只需要 User ~> all 而不再是 User |> Repo.all ,代码如下:

defmodule Ench.Model.Repo do
  defmacro __using__(_) do
    quote do
      @config Application.get_env(:ench, __MODULE__)

      def child_spec do
        :pooler.pool_child_spec([
          name: __MODULE__,
          init_count: @config[:poolsize],
          max_count: @config[:poolsize],
          start_mfa: {
            @config[:adapter], :start_link,
            [@config |> Dict.drop [:adapter, :poolsize]]
          }
        ])
      end

      def __adapter__ do
        @config[:adapter]
      end

      defmacro __using__([table: table_name]) do
        quote do
          use Ench.Model.Table

          def __table__ do
            unquote(table_name)
          end

          def __repo__ do
            unquote(__MODULE__)
          end
        end
      end

    end
  end
end

Read more »

[Elixir ORM #0] 开始

工作中重度使用 Elixir,之前一直是用 erlport 包装了 sqlalchemy ,但在 Elixir 里用起来却非常不舒服,于是转头去研究 ecto ,然后发现几个地方用起来不太舒服,具体哪里就不在这里吐槽了,总之就是决定自己搞一套类 ORM 的东西,因为个人看来 ORM 和 OO 是绝配,不适合在 FP 中搞,写 maru 的时候从语法级别抄 grape 抄出来的不卫生宏的坑还没填上,所以这次只参考 AR 的 query 语法,其它完全针对 Elixir 语言设计。

基本的语法已经设计完成,因为以下三个原因项目不能开源,所以决定写一系列 blog 记录开发流程。

  1. 业务针对性很强,几乎没有通用性。
  2. 使用了 `~>` 和 `<~` 两个运算符,容易和别的库冲突。
  3. 功能极简,作为微服务设计,单项目使用没有优势。

Read more »

C#调用C++ dll 调试

C#程序调用C++的库时一直无法断点调试,在网上搜了各种方法,最终解决方法如下:

启动要调试的exe程序

在VS中选择Debug->Attach To Process, 类型选择Native Code, 选择要调试的进程,点Attach,就可以在C++中断点了.

D3D与OpenGL矩阵,行主序与列主序

D3D中使用行主序矩阵,OpenGL中使用列主序矩阵。两者是反过来的。之前一直纳闷为何跨平台的程序中矩阵不需要进行转置操作,今天终于想明白了。

在两种API中,矩阵的内存存储顺序是相同的,只是解释不同。

假设有二维数组 a 表示矩阵, D3D中第 i 行第 j 列的值存储在 a[i][j] 中,GL则存储在 a[j][i] 中,由此抵消了转置。GL中两个矩阵相乘,P = MN,P[i][j] = Mj列 * Ni行。

对点P平移变换矩阵的内存表示为
M =
[1,0,0,0,
0,1,0,0,
0,0,1,0,
a,b,c,1]

D3D中P为行向量,放在前面  P’x = dot( P , Vec4(M[0], M[4], M[8], M[12]) )
GL中P为列向量 ,放在后面  P’x = dot( Vec4( M[0], M[4], M[8], M[12]), P )
结果是相同的。