Erlang/Elixir 学习 Elixir 有什么新思路么?

chenge · 发布于 2016年11月25日 · 最后由 rupertqin 回复于 2016年12月02日 · 2699 次阅读
4215

最近发现谈论这个语言的多起来了,看了一下,似乎确实值得学习。我注意到对Ruby的一个改进,y=x,修改y不会影响x,就是所谓的Immutable,不知道我理解对了没。

原来一般是找本书学,这次打算跟着那个翻译的Guide来学,大家有什么新思路么?

今天Ruby周刊里看到changelog.com是Elixir开发的,好像是做播客的,还开源了,有兴趣的不妨看看。

======

点滴心得

学习源码

直接跟着源码学,Elixir那些模块是用Elixir语言写的,是最好的学习范本。 而且源码很清楚,直接跟模块是对应的,在lib目录下。

其次再参考

编程练习

推荐下面这个网站,体验很好,难度不大,可参考网友答案,不会停滞不前。

学习资料

推荐

其他参考:

关于Phoenix:

相关资料:

官方提供的免费午餐

一些学习资料

开源书籍:Elixir练习曲,etudes-for-elixir

共收到 26 条回复
11524

你的理解不对。 不过我也讲不好。y无法被修改,对y进行操作的结果是生成一个新的东西,比如z。于是会有x,y,z 这三个东西。

在这里我推荐的书都可以看一下,除了metaprogramming那本。

https://ruby-china.org/topics/31662

96

Elixir里的等号不是赋值,是pattern match,programming elixir里讲等号那章的标题就是

Assignment: I Do Not Think It Means What You Think It Means.”

一句话讲不明白,建议自己看看

Immutable在Erlang里面比较明显

1> X = 1.
1
2> X = 2.
** exception error: no match of right hand side value 2

就是一个“变量”不能被重复赋值,Elixir变量可以重复赋值,但是底层是做了一点小封装吧。

4215

#3楼 @piecehealth 我的意思是x=[1], f(x)修改x,不会影响原来的x。 原来Ruby需要dup,clone这些麻烦。 是个进步,对吧。

96

#4楼 @chenge Erlang里不可能修改x的值 你所谓修改x的值,是指修改x的state,函数编程的特点就是没有state。

比如面向对象编程的话,多次调用person.talk方法,结果会根据person的state改变;函数是编程不存在state,调用一个方法,参数相同,结果永远相同(除非生成随机数这类的特例)这也是所谓的no side-effects,总之不要带着用面向对象编程既定的思路来看函数式编程。

14957

别看翻译的

17365

不能说是进步啊。。如果从底层来看,副作用这种东西是最节约内存的,一般y=x这种操作会使用COW机制,所以一般情况也不会那么的"费内存"。当然你所说的Immutable最适合做并发,函数式可以或起来也是因为这个。

17727

#2楼 @gyorou 为什么说“除了metaprogramming那本”?

11524

#8楼 @theblock24block 凡事都得循序渐进啊。

4215

#10楼 @etnl 谢谢,这个不错。

9522

@chenge 关于 elixir 变量的问题,我写过一篇 blog 希望对你有帮助。https://blog.lazybee.me/elixir-macro-5/

4215

#12楼 @falood 谢谢,很深入啊。

14楼 已删除
15楼 已删除
4215

#1楼 @phoenix 我跟着你的例子学了,比较顺利,感觉写得很好。

96

我想用 Macro 写个 typeof 的函数,但总是报错, 这段代码要怎么改。。 哎特 all

defmodule Mymacro do
  defmacro warp(type) do
    quote do
      def typeof(x) when unquote(:"is_#{type}")(x), do: unquote(type)
    end
  end
end

defmodule Util do
  import Mymacro
  types = ~w[function nil integer binary bitstring list map float atom tuple pid port reference]
  for type <- types do
    warp(type)
  end
end
4215

#17楼 @rupertqin 你的代码的目的是什么?没看懂。

96

#18楼 @chenge 实现一个对象类型检查的 helper

4215

#19楼 @rupertqin type是个字符串,期望输出什么?

错误提示,没看明白啥意思。

** (Protocol.UndefinedError) protocol String.Chars not implemented for {:type, [line: 7], nil}
96

@chenge 实现这样的功能,只是用宏来写循环了

defmodule Util do
  def typeof(x) when is_function(x), do: "function"
  def typeof(x) when is_nil(x), do: "nil"
  def typeof(x) when is_integer(x), do: "integer"
  ...
end

Util.typeof 999
#=> "integer"

4215

#21楼 @rupertqin 感觉不用宏更清楚吧。宏我也不懂,等待高明。

2575

#21楼 @rupertqin 不知道宏该怎么写,但 typeof 这种需求用 Protocols 来做更好吧。 http://elixir-lang.org/getting-started/protocols.html

96

#23楼 @darkbaby123Protocols 好像也要一条条地写每一个判断的 function, 就是不想一条条地写所以用一个循环,我这里纠结的地方在于

如果不在循环里写,是可以用 宏创建一个 function 的:

defmodule Mymacro do
  defmacro warp(type) do
    quote do
      def typeof(x) when unquote(:"is_#{type}")(x), do: unquote(type)
    end
  end
end

defmodule Util do
  import Mymacro
  warp("function")  
end

写在循环里就不行,就很纳闷:

  1. 到底有什么不同?
  2. 怎样动态地用宏创建 function?
2575

#24楼 @rupertqin 我对宏也只是一知半解,但 unquote 还是可用的。一个变通做法如下,来源是这里: http://stackoverflow.com/questions/30498528/how-to-create-a-dynamic-function-name-using-elixir-macro

defmodule Util do
  for type <- ["function", "list", "map"] do
    def typeof(x) when unquote(:"is_#{type}")(x) do
      unquote(type)
    end
  end

  def typeof(_), do: "unknown"
end

IO.puts Util.typeof(fn -> true end)  # function
IO.puts Util.typeof([1, 2, 3])       # list
IO.puts Util.typeof(%{a: 1})         # map
IO.puts Util.typeof(1)               # unknown

关于 DSL 我还是持谨慎态度(并非觉得研究宏没用)。因为我觉得 Elixir 的主张就是 make the complex part explicit 。Jose 在 Domain Specific Language 里拿 validation 举的例子也挺好。

# 1. data structures
import Validator
validate user, name: [length: 1..100],
               email: [matches: ~r/@/]

# 2. functions
import Validator
user
|> validate_length(:name, 1..100)
|> validate_matches(:email, ~r/@/)

# 3. macros + modules
defmodule MyValidator do
  use Validator
  validate_length :name, 1..100
  validate_matches :email, ~r/@/
end

MyValidator.validate(user)

总的来说,数据结构的方式最灵活最容易组合。函数的方式适合复杂的 API ,加上管道运算符也足够描述逻辑。宏的方式实现起来最复杂并且限制最大(想想 conditional validation)。这点其实跟 Ruby 社区近几年更推崇传统的 Object 组合而不是更多的 DSL 是一个意思。

4215

#17楼 @rupertqin #25楼 @darkbaby123 找到解法了,Dave书上有,bind_quoted。

defmodule Mymacro do
  defmacro warp(type) do
    quote bind_quoted: [type: type] do
      def typeof(x) when unquote(:"is_#{type}")(x), do: unquote(type)
    end
  end
end
4215 chenge Elixir 会成为明日之星么?似乎是 中提及了此贴 12月06日 10:42
4215 chenge Elixir 会成为明日之星么?似乎是 中提及了此贴 12月06日 10:42
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册