Programming Elixir, Functional |> Concurrent |> Pragmatic |> Fun, Pragmatic
- 安装配置
- 又是‘Don't worry about details’!最烦这种写法
-
def module Par do
-
def pmap(coll, f) do
- coll |> Enum.map(&(Task.async(fn -> f.(&1) end))) |> Enum.map(&Task.await/1)
-
def pmap(coll, f) do
-
def module Par do
- 调用:result = Par.pmap 1..100, &(&1*&1)
- $iex
- h(Enum.reverse/1)
- $elixir hello.exs
- 又是‘Don't worry about details’!最烦这种写法
- 传统编程
- 模式匹配
- =不是赋值,而是match操作
- var可重新bind到一个subsequent里:a=1, [1,a,3]=[1,2,3] 子作用域名字隐藏?
- 所有value不可变
- list2 = [ 4 | list1]
- 如果process因为heap满而中止,所有数据丢弃,无GC
- 模式匹配
- Basics
- 数据类型:Number, Atom(Symbol?:name), Range(s..e)
- 正则 ~r{regex}opts(选项:f g i m r s u x)
- PID, make-ref
- Tuple: {:ok, 42, "abc"}
- List: [1,2,3]
- 语法糖:[name: "Dave", city: "Dallas"] --> [{:name, "Dave"}, ...]
- Map: %{ key => value, ...} Perl风格?
- colors[:red] --> colors.red
- Binaries
- bin = <<1, 2>>
- bin = << 3 :: size(2), 5 :: size(4), 1 :: size(2)>>
- <<213>>
- :io.format("~-8.2b~n", :binary.bin_to_list(bin2))
- 11010101
- true, false, nil
- 数据类型:Number, Atom(Symbol?:name), Range(s..e)
- 匿名函数
- fn arg-list -> body ... end
- 注意:1)对命名函数不需要f.()语法 2)由于PM机制, fn内可以有多个子句(多重派发?)
- 字符串模板替换(Ruby?):"#{IO.read(file, :line)}"
- 函数返回函数(Currying)
- 函数作为参数(高阶函数)
- &记号:&(Float.round(&1,&2) --> &Float.round/2 (C++11完美转发?)
- fn arg-list -> body ... end
- 模板与命名函数
- do ... end居然不是底层的实际语法??def double(n), do: n*2
- Guard子句:def f(x) when p(x) do ... end
- 默认参数:param \\ defaultValue (编译期的trick?)
- defp 宏
- |> 管道操作
- val |> f(a,b) 基本上相当于f(val, a, b) 插入到第一个参数位置(这有点诡异,对比:F# Java8)
- import List, only:[flatten:1]
- alias Mix.Tasks.DocTest, as: DocTest (alias指令其实就是内置函数?)
- require:引用模块中的宏
- 属性(attributes):@name value 主要用于声明常量?那干嘛叫‘属性’
- *调用Erlang库函数::io.format
- Lists与递归
- def sum(l), do: _sum(l,0)
- defp _sum([], t), do: t ...
- 字典:Maps, HashDicts, Keywords, Sets与Structs
- for p = %{height: height} <- people, height>1.5, do: ...
- Maps不能bind value到key
- new_map = %{ old_map | key => val, ... } 数据结构都是immutable的(对比:Scala)
- @derive Access
- defstruct name: "...", over_18: false
- * put_in, update_in
- Set1 = Enum.into 1..5, HashSet.new
- Types
- 处理集合:Enum与Stream(lazy)
- IO.puts File.open("/path/to/file") |> IO.stream(:line) |> Enum.max_by(&String.length/1)
- File.stream!
- 无限列表:Stream.map
- def sleep(sec) do
-
receive do
- after sec*1000 -> nil
-
receive do
- * Stream.resource
- Comprehensions
- for x <- [...], x<4, do: x*x
- for <<c <- "hello">>, do: >>c>>
- IO.puts File.open("/path/to/file") |> IO.stream(:line) |> Enum.max_by(&String.length/1)
- Strings 与 Binaries
- * Sigils:~-style literals
- 类似于Perl的heredoc:~w """ ...
- utf-8:String.length/codepoints vs byte_size
- 控制流
- if ..., do: .. elese: ...
- cond do ... -> ... end
- case expr do ... -> ... end
- raise RuntimerError, message: "!"
- demo:获取json并格式化显示
- $mix new issues
- 习俗:lib/issues/clci.ex OptionParser.parse
- defmodules Issues.Mixfile do ...
- use Mix.Project
- def project do [ ... ] end
- defp deps do [ { :httpoison, "~> 0.4"] end
- $mix deps.get
- $iex -S mix
- config.exs
- use Mix.Config
- import_config "#{Mix.env}.exs"
- * Enum.sort l, fn, a, b -> a["t"]<b["t"] end
- escript?略
- $mix new issues
- 并发编程
- 多进程
- spawn(M, :fun, [args])
- receive do {sender, msg} -> send sender, {:ok, "Hi"} 这里尾递归
- after 500 -> ... 超时0.5s
- * last = Enum.reduce 1..n, self, fn(_, sendto) -> spawn(M, :f, [sendto]) end
- $ elixir --erl "+P 1000000" -r chain.exs -e "Chain.run(400_000)"
- 用时仅3s?
- > Process.flag(:trap_exit, true)
- spawn_link(子进程结束将导致父终止)
- spawn_monitor (atomic)
- Agent?
- Nodes
- $ iex --sname a1 --cookie secret
- OTP:Servers
- GenServer 6 callbacks:init, handle_call/cast/info, terminate, code_change
- OTP:Supervisors
- OTP:Apps(代码+描述)
- Tasks and Agents
- 多进程
- More Advanced Elixir
- Macros
- IO.inspect
- > quote do: :atom
- > Code.eval_quoted( quote do: [1, 2, unquote([3,4])])
- 实现if宏
-
defmacro myif(cond, clauses) do
- do/else_clause = Keyword.get(clauses, :do/else, nil); 注意,这里是2句话,我笔记缩为1句了
-
quote do
-
case unquote(cond) do
- val when val in [false, nil] -> unquote(else_clause)
-
case unquote(cond) do
-
defmacro myif(cond, clauses) do
- 用Binding注入值
- Macros are Hygienic(类似于Scheme)
- ? 操作符重载(略)
- Macros
- Linking Modules
- use Behaviour
- defcallback ... #声明接口原型?
- __using__
- Trace method calls
Protocols:defprotocol --> defimpl- More Cool Stuff
- TypeSpec and Type Checking