概要
paiza.ioでelixirやってみた。
Kernel.SpecialForms使ってみた。
サンプルコード
defmodule User do
defstruct name: "john", age: 27
end
#%User{}
#%User{} == %{__struct__: User, name: "john", age: 27}
#%User{age: 31}
#=> %{__struct__: User, name: "john", age: 31}
#%User{age: age} = user
#%User{user | age: 28}
#%User{full_name: "john doe"}
#%User{age: age} = user
#%struct_name{} = user
#struct_name #=> User
#%_{} = user
quote do
%{"a" => :b, c: :d}
end
|> IO.inspect
#{:%{}, [], [{"a", :b}, {:c, :d}]}
fun = &Kernel.is_atom/1
fun.(:atom)
|> IO.inspect
#true
fun.("string")
|> IO.inspect
#false
double = &(&1 * 2)
double.(2)
|> IO.inspect
#4
take_five = &Enum.take(&1, 5)
take_five.(1..10)
|> IO.inspect
#[1, 2, 3, 4, 5]
first_elem = &elem(&1, 0)
first_elem.({0, 1})
|> IO.inspect
#0
fun = &(&1 + &2 + &3)
fun.(1, 2, 3)
|> IO.inspect
#6
fun = &{&1, &2}
fun.(1, 2)
|> IO.inspect
#{1, 2}
fun = &[&1 | &2]
fun.(1, [2, 3])
|> IO.inspect
#[1, 2, 3]
String.downcase("FOO")
|> IO.inspect
#"foo"
(fn n -> n end).(7)
|> IO.inspect
#7
Hello.World
|> IO.inspect
#Hello.World
Kernel.Sample
|> IO.inspect
#Kernel.Sample
Kernel.length([1, 2, 3])
|> IO.inspect
#3
Kernel.+(1, 2)
|> IO.inspect
#3
Kernel."+"(1, 2)
|> IO.inspect
#3
negate = fn n ->
-n
end
negate.(7)
|> IO.inspect
#-7
quote do
String.downcase("FOO")
end
|> IO.inspect
#{{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}, [], ["FOO"]}
quote do
negate.(0)
end
|> IO.inspect
#{{:., [], [{:negate, [], __MODULE__}]}, [], [0]}
quote do
Hello.World
end
|> IO.inspect
#{:__aliases__, [alias: false], [:Hello, :World]}
x = :downcase
quote do
String.unquote(x)("FOO")
end
|> IO.inspect
#{{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}, [], ["FOO"]}
x = Sample
quote do
Module.concat(String, unquote(x))
end
|> IO.inspect
#{{:., [], [{:__aliases__, [alias: false], [:Module]}, :concat]}, [], [{:__aliases__, [alias: false], [:String]}, Sample]}
<<1, 2, 3>>
|> IO.inspect
#<<1, 2, 3>>
<<0, "foo">>
|> IO.inspect
#<<0, 102, 111, 111>>
rest = "oo"
<<102, rest::binary>>
|> IO.inspect
#"foo"
<<"foo"::utf16>>
|> IO.inspect
#<<0, 102, 0, 111, 0, 111>>
<<"foo"::utf32>>
|> IO.inspect
#<<0, 0, 0, 102, 0, 0, 0, 111, 0, 0, 0, 111>>
rest = "oo"
|> IO.inspect
#<<102, rest>>
<<102::integer-native, rest::binary>>
|> IO.inspect
<<102::native-integer, rest::binary>>
|> IO.inspect
<<102::unsigned-big-integer, rest::binary>>
|> IO.inspect
<<102::unsigned-big-integer-size(8), rest::binary>>
|> IO.inspect
<<102::unsigned-big-integer-8, rest::binary>>
|> IO.inspect
<<102::8-integer-big-unsigned, rest::binary>>
|> IO.inspect
<<102, rest::binary>>
|> IO.inspect
<<name::binary-size(5), " the ", species::binary>> = <<"Frank the Walrus">>
|> IO.inspect
#"Frank the Walrus"
{name, species}
|> IO.inspect
{"Frank", "Walrus"}
|> IO.inspect
name_size = 5
<<name::binary-size(name_size), " the ", species::binary>> = <<"Frank the Walrus">>
|> IO.inspect
#{name, species}
#{"Frank", "Walrus"}
<<name_size::size(8), name::binary-size(name_size), " the ", species::binary>> = <<5, "Frank the Walrus">>
|> IO.inspect
#{name, species}
#{"Frank", "Walrus"}
#{name_size, <<name::binary-size(name_size), _rest::binary>>} = {5, <<"Frank the Walrus">>}
x = 1
<<x::8>> == <<x::size(8)>>
|> IO.inspect
#true
<<x::8*4>> == <<x::size(8)-unit(4)>>
|> IO.inspect
#true
<<int::integer>> = <<-100>>
|> IO.inspect
#<<156>>
|> IO.inspect
#int
#156
<<int::integer-signed>> = <<-100>>
|> IO.inspect
#<<156>>
#int
#-100
<<-100::signed, _rest::binary>> = <<-100, "foo">>
|> IO.inspect
#<<156, 102, 111, 111>>
<<number::little-integer-size(16)>> = <<0, 1>>
|> IO.inspect
#<<0, 1>>
#number
#256
<<number::big-integer-size(16)>> = <<0, 1>>
|> IO.inspect
#<<0, 1>>
#number
#1
<<"Hello, ", place::binary>> = "Hello, World"
|> IO.inspect
#"Hello, World"
#place
#"World"
defmodule ImageTyper do
@png_signature <<137::size(8), 80::size(8), 78::size(8), 71::size(8), 13::size(8), 10::size(8), 26::size(8), 10::size(8)>>
@jpg_signature <<255::size(8), 216::size(8)>>
def type(<<@png_signature, _rest::binary>>), do: :png
def type(<<@jpg_signature, _rest::binary>>), do: :jpg
def type(_), do: :unknown
end
|> IO.inspect
#ERL_COMPILER_OPTIONS=bin_opt_info mix compile
#left = right(macro)
#^var(macro)
x = 1
x = x + 1
|> IO.inspect
#x
#2
x = 1
^x = List.first([1])
|> IO.inspect
#^x = List.first([2])
x = 0
{x, ^x} = {1, 0}
|> IO.inspect
#x
#1
quote do
Foo.Bar
end
|> IO.inspect
#{:__aliases__, [alias: false], [:Foo, :Bar]}
quote do
Foo.bar()
end
|> IO.inspect
#{{:., [], [{:__aliases__, [alias: false], [:Foo]}, :bar]}, [], []}
quote do
1
2
3
end
|> IO.inspect
#{:__block__, [], [1, 2, 3]}
quote do
{1, 2}
end
|> IO.inspect
#{1, 2}
quote do
{1, 2, 3}
end
|> IO.inspect
#{:{}, [], [1, 2, 3]}
defmodule Math do
alias MyKeyword, as: Keyword
end
#Keyword.values #=> uses MyKeyword.values
#Elixir.Keyword.values #=> uses Keyword.values
alias Foo.Bar.Baz
alias Foo.Bar.Baz, as: Baz
alias Foo.{Bar, Baz, Biz}
alias Foo.Bar
alias Foo.Baz
alias Foo.Biz
#case File.read(file) do
# {:ok, contents} when is_binary(contents) ->
# String.split(contents, "\n")
# {:error, _reason} ->
# Logger.warning "could not find #{file}, assuming empty..."
# []
#end
x = 10
case x do
0 ->
"This clause won't match"
_ ->
"This clause would match any value (x = #{x})"
end
|> IO.inspect
#=> "This clause would match any value (x = 10)"
value = 9
data = {:ok, 8}
case data do
{:ok, value} -> value
:error -> nil
end
value
|> IO.inspect
#=> unbound variable value
value = 7
lucky? = false
case lucky? do
false ->
value = 13
true ->
true
end
value
|> IO.inspect
#=> 7
x = 1
case 10 do
^x -> "Won't match"
_ -> "Will match"
end
|> IO.inspect
#=> "Will match"
#case data do
# value when value in [:one, :two] ->
# "#{value} has been matched"
# :three ->
# "three has been matched"
#end
cond do
hd([1, 2, 3]) ->
"1 is considered as true"
end
|> IO.inspect
#=> "1 is considered as true"
cond do
1 + 1 == 1 ->
"This will never match"
2 * 2 != 4 ->
"Nor this"
true ->
"This will"
end
|> IO.inspect
#=> "This will"
add = fn a, b -> a + b end
add.(1, 2)
|> IO.inspect
#3
negate = fn
true -> false
false -> true
end
negate.(false)
|> IO.inspect
#true
for n <- [1, 2, 3, 4], do: n * 2
|> IO.inspect
#[2, 4, 6, 8]
for n <- [1, 2, 3, 4], do: n * 2
|> IO.inspect
#[2, 4, 6, 8]
for x <- [1, 2], y <- [2, 3], do: x * y
|> IO.inspect
#[2, 3, 4, 6]
for n <- [1, 2, 3, 4, 5, 6], rem(n, 2) == 0, do: n
|> IO.inspect
#[2, 4, 6]
users = [user: "john", admin: "meg", guest: "barbara"]
for {type, name} when type != :guest <- users do
String.upcase(name)
end
|> IO.inspect
#["JOHN", "MEG"]
pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
|> IO.inspect
#[{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
|> IO.inspect
#"helloworld"
for line <- IO.stream(), into: IO.stream() do
String.upcase(line)
end
for x <- [1, 1, 2, 3], uniq: true, do: x * 2
|> IO.inspect
#[2, 4, 6]
for <<x <- "abcabc">>, uniq: true, into: "", do: <<x - 32>>
|> IO.inspect
#"ABC"
letters = for <<x <- "AbCabCABc">>, x in ?a..?z, do: <<x>>
Enum.reduce(letters, %{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
|> IO.inspect
#%{"a" => 1, "b" => 2, "c" => 1}
for <<x <- "AbCabCABc">>, x in ?a..?z, reduce: %{} do
acc -> Map.update(acc, <<x>>, 1, & &1 + 1)
end
|> IO.inspect
#%{"a" => 1, "b" => 2, "c" => 1}
import List
flatten([1, [2], 3])
|> IO.inspect
#[1, 2, 3]
import List
import List, only: :functions
import List, only: :macros
import List, only: [flatten: 1]
import String, except: [split: 2]
import List, only: [flatten: 1, keyfind: 4]
import List, except: [flatten: 1]
import File.Stream, only: [__build__: 3]
defmodule Math do
def some_function do
# 1) Disable "if/2" from Kernel
import Kernel, except: [if: 2]
# 2) Require the new "if/2" macro from MyMacros
#import MyMacros
# 3) Use the new macro
#if do_something, it_works
end
end
quote do
sum(1, 2, 3)
end
|> IO.inspect
#{:sum, [], [1, 2, 3]}
#{:sum, [], [1, 2, 3]}
#:sum #=> Atoms
#1 #=> Integers
#2.0 #=> Floats
#[1, 2] #=> Lists
#"strings" #=> Strings
#{key, value} #=> Tuples with two elements
quote do
unquote("hello")
end
|> IO.inspect
#"hello"
quote unquote: false do
unquote("hello")
end
|> IO.inspect
#{:unquote, [], ["hello"]}
defmodule Math0 do
defmacro squared(x) do
quote do
unquote(x) * unquote(x)
end
end
end
#import Math0
#IO.puts("Got #{squared(5)}")
#import Math0
my_number = fn ->
IO.puts("Returning 5")
5
end
|> IO.inspect
##IO.puts("Got #{squared(my_number.())}")
#squared(my_number.())
my_number.() * my_number.()
defmodule Math do
defmacro squared(x) do
quote do
x = unquote(x)
x * x
end
end
end
defmodule Math do
defmacro squared(x) do
quote bind_quoted: [x: x] do
x * x
end
end
end
quote do
x = unquote(x)
x * x
end
#import Math
#squared(5)
x
defmodule Hygiene do
defmacro no_interference() do
quote do
a = 1
end
end
end
#require Hygiene
a = 10
#Hygiene.no_interference()
a
|> IO.inspect
#=> 10
defmodule NoHygiene do
defmacro interference do
quote do
var!(a) = 1
end
end
end
#require NoHygiene
a = 10
#NoHygiene.interference()
a
|> IO.inspect
#=> 1
defmodule Hygiene do
defmacro write do
quote do
a = 1
end
end
defmacro read do
quote do
a
end
end
end
#Hygiene.write()
#Hygiene.read()
defmodule ContextHygiene do
defmacro write do
quote do
var!(a, ContextHygiene) = 1
end
end
defmacro read do
quote do
var!(a, ContextHygiene)
end
end
end
#ContextHygiene.write()
#ContextHygiene.read()
#=> 1
defmodule Hygiene do
alias Map, as: M
defmacro no_interference do
quote do
M.new()
end
end
end
#require Hygiene
#Hygiene.no_interference()
#=> %{}
defmodule Hygiene do
alias Map, as: M
defmacro no_interference do
quote do
M.new()
end
end
end
#require Hygiene
alias SomethingElse, as: M
#Hygiene.no_interference()
#=> %{}
defmodule Hygiene do
# This will expand to Elixir.Nested.hello()
defmacro no_interference do
quote do
Nested.hello()
end
end
# This will expand to Nested.hello() for
# whatever is Nested in the caller
defmacro interference do
quote do
alias!(Nested).hello()
end
end
end
defmodule Parent do
defmodule Nested do
def hello, do: "world"
end
require Hygiene
#Hygiene.no_interference()
#Hygiene.interference()
#=> "world"
end
defmodule Hygiene do
defmacrop get_length do
quote do
#length([1, 2, 3])
end
end
def return_length do
import Kernel, except: [length: 1]
get_length
end
end
Hygiene.return_length()
#=> 3
#def return_length do
# import String, only: [length: 1]
# get_length
#end
defmodule Lazy do
defmacrop get_length do
import Kernel, except: [length: 1]
quote do
length("hello")
end
end
def return_length do
import Kernel, except: [length: 1]
import String, only: [length: 1]
get_length
end
end
#Lazy.return_length()
#|> IO.inspect
#=> 5
# adder.ex
defmodule Adder do
@doc "Defines a function that adds two numbers"
defmacro defadd do
quote location: :keep do
def add(a, b), do: a + b
end
end
end
# sample.ex
defmodule Sample do
import Adder
defadd
end
#require Sample
#Sample.add(:one, :two)
#|> IO.inspect
kv = [foo: 1, bar: 2]
#Enum.each(kv, fn {k, v} ->
# def unquote(k)(), do: unquote(v)
#end)
#defmacro defkv(kv) do
# Enum.map(kv, fn {k, v} ->
# quote do
# def unquote(k)(), do: unquote(v)
# end
# end)
#end
#defkv [foo: 1, bar: 2]
#kv = [foo: 1, bar: 2]
#defmacro defkv(kv) do
# quote do
# Enum.each(unquote(kv), fn {k, v} ->
# def unquote(k)(), do: unquote(v)
# end)
# end
#end
#defmacro defkv(kv) do
# quote bind_quoted: [kv: kv] do
# Enum.each(kv, fn {k, v} ->
# def unquote(k)(), do: unquote(v)
# end)
# end
#end
#receive do
# {:selector, number, name} when is_integer(number) ->
# name
# name when is_atom(name) ->
# name
# _ ->
# IO.puts(:stderr, "Unexpected message received")
#end
#receive do
# {:selector, number, name} when is_integer(number) ->
# name
# name when is_atom(name) ->
# name
#_ ->
# IO.puts(:stderr, "Unexpected message received")
#after
# 5000 ->
# IO.puts(:stderr, "No message in 5 seconds")
#end
#defmodule Math do
# require MyMacros
# MyMacros.if do_something, it_works
#end
value =
quote do
13
end
quote do
sum(1, unquote(value), 3)
end
|> IO.inspect
#{:sum, [], [1, 13, 3]}
value = %{foo: :bar}
quote do
process_map(unquote(Macro.escape(value)))
end
|> IO.inspect
#{:process_map, [], [{:%{}, [], [foo: :bar]}]}
values = [2, 3, 4]
quote do
sum(1, unquote_splicing(values), 5)
end
|> IO.inspect
#{:sum, [], [1, 2, 3, 4, 5]}
opts = %{width: 10, height: 15}
with {:ok, width} <- Map.fetch(opts, :width), {:ok, height} <- Map.fetch(opts, :height) do
{:ok, width * height}
end
|> IO.inspect
#{:ok, 150}
opts = %{width: 10}
with {:ok, width} <- Map.fetch(opts, :width), {:ok, height} <- Map.fetch(opts, :height) do
{:ok, width * height}
end
|> IO.inspect
#:error
users = %{"melany" => "guest", "bob" => :admin}
with {:ok, role} when not is_binary(role) <- Map.fetch(users, "bob") do
{:ok, to_string(role)}
end
|> IO.inspect
#{:ok, "admin"}
width = nil
opts = %{width: 10, height: 15}
with {:ok, width} <- Map.fetch(opts, :width), double_width = width * 2, {:ok, height} <- Map.fetch(opts, :height) do
{:ok, double_width * height}
end
|> IO.inspect
{:ok, 300}
width
|> IO.inspect
#nil
#with :foo = :bar, do: :ok
opts = %{width: 10, height: 15}
with({:ok, width} <- Map.fetch(opts, :width), {:ok, height} <- Map.fetch(opts, :height)) do
{:ok, width * height}
end
|> IO.inspect
{:ok, 150}
opts = %{width: 10}
with {:ok, width} <- Map.fetch(opts, :width), {:ok, height} <- Map.fetch(opts, :height) do
{:ok, width * height}
else
:error ->
{:error, :wrong_data}
_other_error ->
:unexpected_error
end
|> IO.inspect
#{:error, :wrong_data}
実行結果
{:%{}, [], [{"a", :b}, {:c, :d}]}
true
false
4
[1, 2, 3, 4, 5]
0
6
{1, 2}
[1, 2, 3]
"foo"
7
Hello.World
Kernel.Sample
3
3
3
-7
{{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}, [], ["FOO"]}
{{:., [], [{:negate, [], Elixir}]}, [], [0]}
{:__aliases__, [alias: false], [:Hello, :World]}
{{:., [], [{:__aliases__, [alias: false], [:String]}, :downcase]}, [], ["FOO"]}
{{:., [], [{:__aliases__, [alias: false], [:Module]}, :concat]}, [],
[{:__aliases__, [alias: false], [:String]}, Sample]}
<<1, 2, 3>>
<<0, 102, 111, 111>>
"foo"
<<0, 102, 0, 111, 0, 111>>
<<0, 0, 0, 102, 0, 0, 0, 111, 0, 0, 0, 111>>
"oo"
"foo"
"foo"
"foo"
"foo"
"foo"
"foo"
"foo"
"Frank the Walrus"
{"Frank", "Walrus"}
{"Frank", "Walrus"}
"Frank the Walrus"
<<5, 70, 114, 97, 110, 107, 32, 116, 104, 101, 32, 87, 97, 108, 114, 117, 115>>
<<1>>
<<0, 0, 0, 1>>
<<156>>
<<156>>
<<156>>
<<156, 102, 111, 111>>
<<0, 1>>
<<0, 1>>
"Hello, World"
{:module, ImageTyper,
<<70, 79, 82, 49, 0, 0, 5, 200, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 157,
0, 0, 0, 17, 17, 69, 108, 105, 120, 105, 114, 46, 73, 109, 97, 103, 101, 84,
121, 112, 101, 114, 8, 95, 95, 105, 110, ...>>, {:type, 1}}
2
1
{1, 0}
{:__aliases__, [alias: false], [:Foo, :Bar]}
{{:., [], [{:__aliases__, [alias: false], [:Foo]}, :bar]}, [], []}
{:__block__, [], [1, 2, 3]}
{1, 2}
{:{}, [], [1, 2, 3]}
"This clause would match any value (x = 10)"
9
7
"Will match"
"1 is considered as true"
"This will"
3
true
2
4
6
8
2
4
6
8
2
3
4
6
2
4
6
["JOHN", "MEG"]
{213, 45, 132}
{64, 76, 32}
{76, 0, 0}
{234, 32, 15}
"h"
"e"
"l"
"l"
"o"
"w"
"o"
"r"
"l"
"d"
2
2
4
6
"A"
"B"
"C"
"A"
"B"
"C"
%{"a" => 1, "b" => 2, "c" => 1}
%{"a" => 1, "b" => 2, "c" => 1}
[1, 2, 3]
{:sum, [], [1, 2, 3]}
"hello"
{:unquote, [], ["hello"]}
#Function<15.40727452 in file:Main.exs>
Returning 5
Returning 5
10
10
{:sum, [], [1, 13, 3]}
{:process_map, [], [{:%{}, [], [foo: :bar]}]}
{:sum, [], [1, 2, 3, 4, 5]}
{:ok, 150}
:error
{:ok, "admin"}
{:ok, 300}
nil
{:ok, 150}
{:error, :wrong_data}
成果物
以上。