1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

paiza.ioでelixir その187

Last updated at Posted at 2023-02-21

概要

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}

成果物

以上。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?