关于elixir:使用-Phoenix-LiveView-构建-Instagram-4

应用PETAL(Phoenix、Elixir、TailwindCSS、AlpineJS、LiveView)技术栈构建一个简化版的Instagram Web应用程序<!--more--> 在第 3 局部中,咱们增加了个人资料页面以及关注和显示帐户的性能,在这部分中,咱们将解决用户的帖子。您能够赶上Instagram 克隆 GitHub Repo。 让咱们首先增加一个路由来显示用于增加帖子的表单,关上lib/instagram_clone_web/router.ex: scope "/", InstagramCloneWeb do pipe_through :browser live "/", PageLive, :index live "/:username", UserLive.Profile, :index live "/p/:id", PostLive.Show # <-- THIS LINE WAS ADDED end scope "/", InstagramCloneWeb do pipe_through [:browser, :require_authenticated_user] get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email live "/accounts/edit", UserLive.Settings live "/accounts/password/change", UserLive.PassSettings live "/:username/following", UserLive.Profile, :following live "/:username/followers", UserLive.Profile, :followers live "/p/new", PostLive.New # <-- THIS LINE WAS ADDED end在文件夹中创立咱们的实时视图文件lib/instagram_clone_web/live/post_live: ...

September 1, 2023 · 6 min · jiezi

关于elixir:使用-Phoenix-LiveView-构建-Instagram-2

应用PETAL(Phoenix、Elixir、TailwindCSS、AlpineJS、LiveView)技术栈构建一个简化版的Instagram Web应用程序<!--more--> 在第 1 局部中,咱们已实现所有设置并筹备好根本布局,让咱们开始解决用户设置。您能够赶上Instagram 克隆 GitHub Repo。 让咱们首先创立路由,关上lib/instagram_clone_web/router.ex并在范畴下增加以下 2 条路由:require_authenticated_user: scope "/", InstagramCloneWeb do pipe_through [:browser, :require_authenticated_user] get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email live "/accounts/edit", UserLive.Settings live "/accounts/password/change", UserLive.PassSettings end而后咱们须要创立这些 liveview 文件,在该文件夹内创立一个名为user_liveunder 的文件夹lib/instagram_clone_web/live,增加以下 4 个文件: lib/instagram_clone_web/live/user_live/settings.ex lib/instagram_clone_web/live/user_live/settings.html.leex lib/instagram_clone_web/live/user_live/pass_settings.ex lib/instagram_clone_web/live/user_live/pass_settings.html.leex 在咱们的导航题目中,咱们须要链接到该新路线,lib/instagram_clone_web/live/header_nav_component.html.leex在第 60 行关上,将以下内容增加到Settings live_patch to: <%= live_patch to: Routes.live_path(@socket, InstagramCloneWeb.UserLive.Settings) do %> <li class="py-2 px-4 hover:bg-gray-50">Settings</li><% end %>当初,当咱们拜访该链接时,咱们应该会呈现谬误,因为文件是空的,因而关上lib/instagram_clone_web/live/user_live/settings.ex并增加以下内容: defmodule InstagramCloneWeb.UserLive.Settings do use InstagramCloneWeb, :live_view @impl true def mount(_params, session, socket) do socket = assign_defaults(session, socket) {:ok, socket} endend当初咱们应该有一个空白页面,只有顶部导航栏,所以让咱们开始工作吧。 ...

September 1, 2023 · 11 min · jiezi

关于elixir:使用-Phoenix-LiveView-构建-Instagram-1

应用PETAL(Phoenix、Elixir、TailwindCSS、AlpineJS、LiveView)技术栈构建一个简化版的Instagram Web应用程序<!--more--> 更好的学习办法是亲自动手构建货色,让咱们应用很棒的 PETAL(Phoenix、Elixir、TailwindCSS、AlpineJS、LiveView)堆栈构建一个简化版的 Instagram Web 应用程序,并深刻理解函数式的黑暗世界编程和最热门的孩子在凤凰框架与LiveView。 我不认为本人是一名老师,也不是任何方面的专家,我只是一个像你一样的普通人。任何人都能够遵循,即便您可能会被整个堆栈吓倒,这是一种新技术,不是很风行,而且没有很多资源和资料。如果您是一位经验丰富的开发人员,那么您不会有任何问题,这并不意味着如果您是初学者,您就无奈跟上,我会尽力使其对初学者敌对,但我不会具体介绍堆栈的每个基础知识或网络开发,所以你曾经被正告了。 Elixir 是我有幸学习和尝试的最好的语言之一,我想与世界分享我的激情,我心愿其他人能感触到我对这门语言的感触。 免责申明: Elixir、函数式编程、Phoenix 框架,可能听起来、看起来很艰难和简单,但它基本不是,比其余任何货色都容易,它可能不适宜每个人,因为咱们的想法并不相同,但对于那些认为就像我尝试的感觉一样。TailwindCSS 可能有些回心转意,看起来不值得尝试,我晓得,因为我也是这么感觉的,但只有尝试一下,你用得越多,它就会变得越有意义,你就会越喜爱它,它让 CSS 变得不简单,让你不放弃前端开发,CSS依然会很苦楚,作为开发者,咱们没有急躁把UI弄好,但它是一股新鲜空气。 咱们不会在本文中实现整个我的项目,这将是一系列文章,因而这将是第 1 局部。我假如您有本人的开发环境,装置了 Elixir,我的开发环境是在带有 WSL 的 Windows 10 上。咱们将尽力尽可能具体,但放弃简略,这仅用于学习目标,因而它不会是准确的正本,也不会具备所有性能,咱们将尽可能靠近实在的货色,也咱们不会专一于使网站具备响应能力,咱们只会使其实用于大屏幕。 让咱们首先转到终端并应用 LiveView 创立一个新的 Phoenix 应用程序。 $ mix phx.new instagram_clone --live 装置并获取所有依赖项后。 $ cd instagram_clone && mix ecto.create 我创立了一个 GitHub 存储库,您能够在此处拜访Instagram 克隆 GitHub 存储库,您能够随便应用代码,欢送奉献。 让咱们运行服务器以确保一切正常。 $ iex -S mix phx.server 如果没有谬误,当您拜访 http://localhost:4000/ 时,您应该会看到默认的 Phoenix 框架主页 我应用 Visual Studio Code,因而我将应用以下命令关上我的项目文件夹。 $ code . 当初让咱们在 mix.exs 文件中增加混合依赖项。 ...

September 1, 2023 · 14 min · jiezi

关于elixir:译-Nx-入门-Sean-Moriarity

Nx 是一个 BEAM 上的,用于操作张量(tensor)和数值计算的新库。Nx 冀望为elixir、erlang以及其它 BEAM 语言关上一扇大门,通往一个簇新的畛域 -- 用户可能应用 JIT 和高度特殊化的 tensor 操作来减速他们的代码。本文中,你会学到根底的操作 Nx 的办法,以及如何将其用于机器学习利用中。 适应 TensorNx 的 Tensor 相似于 PyTorch 或 TensorFlow 的 tensor,NumPy 的多维数组。用过它们,那就好办。不过它与数学定义不完全一致。Nx 从 Python 生态里借鉴了许多,所以适应起来应该是很容易。Elixir 程序员能够把 tensor 设想为嵌套列表,附带了一些元数据。 iex> Nx.tensor([[1, 2, 3], [4, 5, 6]])#Nx.Tensor< s64[2][3] [ [1, 2, 3], [4, 5, 6] ]>Nx.tensor/2 是用来创立 tensor 的,它能够承受嵌套列表和标量: iex> Nx.tensor(1.0)#Nx.Tensor< f32 1.0>元数据在 tensor 被检视时能够看到,比方例子里的 s64[2][3] 和 f32。Tensor 有形态和类型。每个维度的长度所组成的元祖形成了形态。在下面的例子里第一个 tensor 的形态是 {2, 3},示意为 [2][3]: iex> Nx.shape(Nx.tensor([[1, 2, 3], [4, 5, 6]])){2, 3}把 tensor 设想为嵌套列表的话,就是两个列表,每个蕴含3个元素。嵌套更多: ...

February 18, 2023 · 5 min · jiezi

关于elixir:使用-Phoenix-LiveBook-做一个小实验-实时编码部署http服务

LiveBook 是 elixir 团队新推出的一款利用,能够应用它很不便地在浏览器中编写文章,并且在其中运行 elixir 代码。 我很好奇是否应用 LiveBook 间接更改以后服务器的路由配置,使得咱们能够实现实时部署服务。比方咱们在 LiveBook 里写好一个页面,而后间接配置到某个 url 门路上,他人就能够拜访到。这样感觉十分酷,省去了繁琐的配置打包和公布的流程,而且从实践上是齐全能够实现的。 说干就干,首先我在 fly.io 上部署了一个收费的 livebook 实例,你也能够在本地部署,很不便的。 启动之后在左侧的配置按钮里抉择 Runtime settings,选则 Embedded。即在 livebook 自身的 erlang node 里执行代码。livebook 为了保障安全性和隔离性,默认是会另启动一个 node 来执行代码的,也就是 Elixir standalone 选项,但这样咱们是无奈批改路由配置的。 批改好之后,我新建了一个文档,就能够开始写代码了。Livebook 应用的是 Phoenix 框架,其底层的 HTTP 服务器是 Cowboy,再底层是 ranch。所以咱们先通过 :ranch.info() 来获取以后服务器的一些信息。从返回值里咱们晓得了以后的 ranch server 的ref是 LivebookWeb.Endpoint.HTTP,所有的路由(或者叫散发 Dispatch) 配置都是在这外面保留。下一步咱们就能够对 dispatch 配置进行批改。 每个http申请都会被散发到不同的 handler(这个怎么翻译来着,抓手?),所以咱们首先须要写一个用于测试的 handler。 defmodule TestHandler do @behaviour :cowboy_handler def init(req, state) do req = :cowboy_req.reply(200, %{ "content-type" => "text/plain" }, "Hello World!", req) {:ok, req, state} endend它的性能非常简单,无论收到什么都返回你好世界。接下来将它配置到咱们的 dispatch 外面,留神要保留之前的 dispatch 内容,否则咱们的 livebook 就拜访不了了哈哈。 ...

June 13, 2022 · 1 min · jiezi

关于elixir:了解Flow-elixir的并行计算库

“咱们不短少计算机,短少的是聪慧地应用计算机的办法。”日常编程的时候,我有时候会不盲目的把计算机当成一个人,以对人谈话的形式来给计算机布置任务。然而,计算机和人类的一个次要区别就是,它会一字不差地执行程序,遇到非凡状况时不会做变通。 比方咱们想统计一个文件里的词频,最直观的形式就是: File.stream!("path/to/some/file")|> Enum.flat_map(&String.split(&1, " "))|> Enum.reduce(%{}, fn word, acc -> Map.update(acc, word, 1, & &1 + 1)end)|> Enum.to_list()第一行是应用 File.stream!/1 关上文件,它能够让咱们逐行读取文件,这一步不会把文件内容读取进去。第二行就不得了了,会把文件的全部内容都读取到内存中。在这里如果文件过大,有可能间接就撑爆内存了。 File.stream!("path/to/some/file")|> Stream.flat_map(&String.split(&1, " "))|> Enum.reduce(%{}, fn word, acc -> Map.update(acc, word, 1, & &1 + 1)end)|> Enum.to_list()既然 Enum.flat_map/2 太过暴力,咱们就用 Stream.flat_map/2 来代替它,这样,在第二行仍旧不会读取任何文件内容。到第三行的 Enum.reduce/3 这里会开始逐行读取文件内容并且应用一个 hash map 来统计词频。这样做根本不会呈现内存爆炸的状况了。当初的处理器根本都是多核的,咱们能不能把多核处理器利用起来呢? 不便起见,咱们用上面这个列表示意文件的每一行(只管这样就无奈体现出解决大文件的特点了,但咱们只有晓得程序不会一下子读取全部内容到内存就行了) data = [ "rose are red", "violets are blue"]第一步,和 Stream 相似,咱们生成一个 lazy 的 Flow 数据结构: opts = [stages: 2, max_demand: 1]flow = flow |> Flow.from_enumerable(opts)%Flow{ operations: [], options: [stages: 2, max_demand: 1], producers: {:enumerables, [["rose are red", "violets are blue"]]}, window: %Flow.Window.Global{periodically: [], trigger: nil}}stages 能够了解为并行的外围数量,实质上是参加并行处理的gen_stage 过程数量。这里咱们设置为2,与双核机器上的默认配置雷同。 ...

May 10, 2022 · 2 min · jiezi

关于elixir:elixir-0083-Streamtransform-的用法

在 elixir 里能够用 Stream 来示意有限长的序列,例如 0,1,2,3... 就能够示意为: iex> s = Stream.iterate(0, & &1 + 1)#Function<62.50989570/2 in Stream.unfold/2>如果咱们想要计算这个数列中每5个数的和,就能够应用 Stream.transform 函数: iex> s1 = Stream.transform(s, {0, 0}, fn x, {sum, count} ->...> if count == 5 do ...> {[sum], {x, 1}} ...> else...> {[], {sum + x, count + 1}} ...> end...> end)#Function<60.50989570/2 in Stream.transform/3>iex> Enum.take(s1, 10)[10, 35, 60, 85, 110, 135, 160, 185, 210, 235]它是 Enum.flat_map_reduce 的 Stream 版本。

December 26, 2021 · 1 min · jiezi

关于elixir:elixir-0082-application-controller-应用是如何被载入和启动的

相熟 erlang/elixir 的敌人们应该晓得 application 的概念,它是一种非凡的构造,用于启动和进行一个利用。每当咱们新建一个 erlang/elixir 我的项目,也同时新建了一个同名的 利用。在应用依赖库的时候,个别每个依赖库也是一个利用,会在咱们运行我的项目时被载入和启动。 那么,erlang是如何治理这些利用的呢?这就是 :application_controller 发挥作用的中央了。所有的利用的载入、启动等状态的保留和变更,都要通过这个过程。 # 列出以后的全副利用状态> :application_controller.info()虚利用不是所有的利用都会启动过程树,有些利用即便处于 :started 状态,也没有启动任何过程。权且称这种利用为虚利用吧。 跟踪利用我之前文章里提到的 bony_trance 库来跟踪一下 在load 和 start 一个利用时,:application_controller 过程都做了什么吧。 stop 利用iex(3)> :application_controller.stop_application :play#PID<0.44.0> RECEIVED +67.069019sMESSAGE: {:"$gen_call", {#PID<0.199.0>, #Reference<0.2783639343.3287547907.121340>}, {:stop_application, :play}}#PID<0.44.0> SENT TO: :code_server +0.000047sMESSAGE: {:code_call, #PID<0.44.0>, {:ensure_loaded, Logger.Translator}}#PID<0.44.0> RECEIVED +0.004582sMESSAGE: {:code_server, {:module, Logger.Translator}}#PID<0.44.0> SENT TO: :code_server +0.000033sMESSAGE: {:code_call, #PID<0.44.0>, {:ensure_loaded, Logger.Utils}}#PID<0.44.0> RECEIVED +0.002413sMESSAGE: {:code_server, {:module, Logger.Utils}}#PID<0.44.0> SENT TO: :code_server +0.000012sMESSAGE: {:code_call, #PID<0.44.0>, {:ensure_loaded, :calendar}}#PID<0.44.0> RECEIVED +0.012388sMESSAGE: {:code_server, {:module, :calendar}}12:38:54.714 [info] Application play exited: :stopped:ok#PID<0.44.0> SENT TO: Logger +0.000015sMESSAGE: {:notify, {:info, #PID<0.64.0>, {Logger, ["Application ", "play", " exited: " | ":stopped"], {{2021, 11, 28}, {12, 38, 54, 714}}, [erl_level: :notice, domain: [:otp], error_logger: %{report_cb: &:application_controller.format_log/1, tag: :info_report, type: :std_info}, file: "application_controller.erl", function: "info_exited/3", gl: #PID<0.64.0>, line: 2119, mfa: {:application_controller, :info_exited, 3}, module: :application_controller, pid: #PID<0.44.0>, report_cb: &:application_controller.format_log/2, time: 1638074334714339]}}}#PID<0.44.0> SENT TO: #PID<0.199.0> +0.000015sMESSAGE: {#Reference<0.2783639343.3287547907.121340>, :ok}首先向 code_server 确认一些必要的用于打印log的模块是已载入的, 这一步的后果会缓存,之后不用反复询问。如果该利用有 application 过程,则会向其发送 :stop 音讯。最初打印出利用已进行的log。 ...

November 28, 2021 · 2 min · jiezi

关于elixir:elixir-0080-读-erlang-开发团队博客-之-N-对-1-并行消息的性能优化

自从 erlang OTP 团队开设技术博客以来,很多高质量的文章让咱们有机会可能理解 erlang 外部的各种机制。 譬如最近的这篇 https://www.erlang.org/blog/p... ,就讲述了在 erlang 虚拟机中是如何对 “N对1” 的过程消息传递进行性能优化的。 本文只是站在笔者的角度对文章内容进行转述,如有了解谬误或者不到位的中央,敬请在评论中指出。 下面这张图很直观地体现了优化的成果,这是在多核机器上,很多过程同时向一个过程发送短消息的性能比照。其中横轴是过程数量,纵轴是每秒操作数。能够看到在优化后,曾经实现了程度扩大,即过程数量越多,每秒操作数越多。而在优化之前,过程数越多,性能越低。 在深刻理解这个优化是如何做到的之前,先来理解一下 erlang 虚拟机中的信号(signal)机制。 在 erlang 虚拟机中,实体(entity)代表所有并发执行的货色,包含过程、Port 等等。一般的过程音讯也是一种信号。信号的程序遵循以下规定: 如果实体 A 先发送信号 S1 给 B, 而后发送 S2 给 B。那么 S1 保障不会在 S2 之后达到。 艰深地讲,设想一条N个车道的公路,不容许超车,那么在同一条车道上,汽车的程序是肯定的;而不同车道之间,汽车的前后总是在变动。 下图是在优化之前,一个过程内简略构造。 过程发送音讯的步骤是这样的: 调配一个链表的节点,其中蕴含信号获取外信号队列(OuterSinalQueue)的锁将信号节点增加到外信号队列的前面开释锁。过程收取音讯的步骤是这样的: 获取外信号队列的锁将外信号队列的内容增加到内信号队列(InnerSinalQueue)前面开释锁。以上是选项 {message_queue_data, off_heap} 开启时的机制。而默认的选项是 {message_queue_data, on_heap}, 本次的这个优化其实只作用于 off_heap 的状况,也就是如果咱们没有对 message_queue_data 这个选项进行配置,那么这个优化就和咱们无关。那么默认状况下的消息传递步骤是什么呢?尽管和这个优化无关,但文章里还是具体介绍了一下: 发送音讯的步骤: 尝试用 try_lock 来获取主过程锁(MainProcessLock)。如果胜利:1.在过程的主堆(main heap)上为信号调配空间,并将信号复制到那里2.调配一个链表节点,蕴含指向那个信号的地位的指针3.获取外信号队列锁4.将信号节点增加到外信号队列的前面5.开释外信号队列锁6.开释主过程锁如果失败:1.调配一个链表的节点,其中蕴含信号2.获取外信号队列锁3.将信号节点增加到外信号队列的前面4.开释外信号队列锁。能够看出 on_heap 的益处就是在获取主过程锁胜利的状况下,信号数据被间接复制到了过程的主堆上。害处就是须要获取主过程锁,来避免在这个过程中产生垃圾回收。所以,在十分多的过程同时给一个过程发消息的时候,off_heap具备更好的扩展性,因为不须要去争抢接收者的主过程锁。 尽管如此,外信号队列锁仍旧是一个性能瓶颈。 上面咱们能够聊聊如何优化了。 回顾咱们之前提到的 erlang 虚拟机对于信号程序的要求,能看出咱们须要的是一条N车道的公路,当初却只有一个收费站(接收者的外信号队列锁),车全堵在这了。优化的计划显然也跃然纸上了,就是减少“收费站“的数量。通过简略地对发送者过程的pid做哈希,将信号分流到64个 slot 队列中。 只有在同时获取外信号队列的过程数量超过肯定阈值的时候,此优化才会被触发。 ...

November 12, 2021 · 1 min · jiezi

关于elixir:elixir-0078-elixir-版本升级的历程111-112

想平常一样关上 github,发现我最喜爱的编程语言 elixir 公布了新的版本。立马下载安装,没想到一运行公司的我的项目,爆了一堆谬误。 1首先看到的是: warning: ^^^ is deprecated. It is typically used as xor but it has the wrong precedence, use Bitwise.bxor/2 instead查了一下 Changelog,原来这个函数曾经被淘汰了,像提醒里说的那样改为 Bitwise.bxor/2 就能够了。 2而后 elixir 1.12 版本修改了一个对于 behaviour 的bug。之前如果某个 callback 的实现函数没有标注 @impl true 的话是不会有正告的。当初会报: warning: module attribute @impl was not set for function xxx/2 callback (specified in XXX). This either means you forgot to add the "@impl true" annotation before the definition or that you are accidentally overriding this callback咱们把 @impl true 在对应函数下面加上就能够了。 ...

October 13, 2021 · 1 min · jiezi

关于elixir:Elixir-bcryptelixir-在-windows-中的-Compile-错误

形容 开发 Elixir 的时候,根本都是在 MacOS 或者 Linux 下。对于 bcrypt_elixir 这个包 须要用到 nmake 去构建和编译。 装置必须工具 先去下载安装 Microsoft Visual Studio, 我这里装置的是2019的。为了必须的 nmake 须要装置 应用 C++ 的桌面开发. 装置实现后,先设置 nmake到环境变量中。 如果不晓得 nmake 在哪,能够关上资源管理器 去到 C:\Program Files (x86)\Microsoft Visual Studio\2019 而后通过搜寻栏搜素 nmake.exe. 这里找到了4个,有两个是 x86 文件夹下, 两个是 x64 文件夹下. 具体设置那个到环境变量中,应用对应零碎是多少位的那个。例如我这里是 x64 文件夹下的。 设置后,从新 应用 mix deps.get 命令,可能提醒你须要应用 cmd /k "C:\Program Files (x86)\....\vcvarsall.bat" amd64 如果呈现下面提醒,跟着它操作就行了。只是把两头的 "C:\Program Files (x86)....\vcvarsall.bat" 换成你零碎中 vcvarsall.bat 所在的目录。也是去下面那个 2019 中搜寻进去。 最初就是执行 mix deps.compile 从新编译之前的 bcrypt_elixir 包了。 我这里中途呈现了 modules base64url not found 的问题,引入了base64url 包都不行。然而执行下面后,从新执行 mix compile, 而后 mix deps.get 后又能够了,起因不明。 ...

May 20, 2021 · 1 min · jiezi

关于elixir:遍历语法树的两种方式-prewalk-和-postwalk

在编辑形象语法树(AST) 的时候, 咱们常常须要遍历整个构造, elixir 规范库中提供了两种遍历形式. 举个例子, 有这样一个 AST: quote do add(1, 2)endquote 后的数据结构是这样: {:add, [], [1, 2]}用图像示意的话, 大略就是这样, 有很显著的层级关系: Prewalkprewalk 就是以从外层到内层的程序, 进行遍历. 留神最初返回的元组里, 第二个参数才是咱们的 acc. iex(5)> Macro.prewalk(ast, [], fn ...(5)> x, acc ->...(5)> {x, acc ++ [x]}...(5)> end...(5)> ){{:add, [], [1, 2]}, [{:add, [], [1, 2]}, 1, 2]}postwalk 正相反, 是从外向外遍历. iex(6)> Macro.postwalk(ast, [], fn...(6)> x, acc -> ...(6)> {x, acc ++ [x]} ...(6)> end ...(6)> ){{:add, [], [1, 2]}, [1, 2, {:add, [], [1, 2]}]}

February 26, 2021 · 1 min · jiezi

关于elixir:追求速度的极限-在elixir里使用-atomics-模块操作-mutable-数据

在 elixir 中罕用的数据结构都是不可变(immutable)的,也就是每次批改实际上是在内存中新建一个数据。不可变数据的益处是能够防止副作用,不便测试,缩小bug。毛病也很显著,就是速度慢。 例如 advent of code 2020 的第23天Part2 这道题,通过应用可变的数据结构,能够大幅晋升速度。 题目粗心是:给定一个数列,结尾9个数是 “389125467”,前面是 10 到 1百万,最初一个数连贯到结尾造成环。以 3 为以后数,执行以下操作 100 百万次 —— “将以后数左边3个数拿起,而后在残余的数字里寻找一个指标数,它比以后数小,且值最靠近,如果没有,则返回最大的数。将拿起的3个数插入到指标数的左边。以以后数左边的数作为新的以后数。” 在 elixir 里是无奈间接操作链表指针的,但咱们能够用 map 来模仿一个单链表: defmodule MapList do def new do %{} end def put(s, a, next) do Map.put(s, a, next) end def find(s, a) do Map.get(s, a) end def exchange(s, a, x) do Map.get_and_update!(s, a, fn c -> {c, x} end) end end上面是理论的解题逻辑: ...

December 30, 2020 · 2 min · jiezi

关于elixir:使用-Elixir-推导-Y-组合子

如何递归调用匿名函数,这个问题困扰我很久了。直到我据说了 Y 组合子。 一般的递归函数是这样的: defmodule M do def foo(x) do case x do 0 -> 0 n -> foo(n-1) + n end endend而后我一步步把它革新成匿名函数,首先,函数体大抵不会变: foo = fn x -> case x do 0 -> 0 n -> foo.(n-1) + n endend这里第二个 foo 的中央应该是 foo 这个函数自身被递归调用,然而这个时候 foo 的定义还没有实现。没关系,遇到不晓得的货色,就把它作为参数吧。 所以咱们批改了函数的定义,让它首先从参数 g 承受它自身的定义,因为 g 就是 bar, 为了失去下面的本来的 foo , 须要将它自身作为参数传递给本人,用 g.(g) 来失去 foo。 这里有点绕,可能须要多看几遍。 bar = fn g -> # 上一步里的 foo 从这里开始 fn x -> case x do 0 -> 0 n -> g.(g).(n-1) + n end endendbaz = bar.(bar)接下来想方法先把 g.(g)这个货色替换掉,替换的准则是不扭转运行时的执行逻辑: ...

December 29, 2020 · 2 min · jiezi

关于elixir:Advent-of-code-2020-elixir-解法回顾-上

Advent of code 2020 elixir 解法回顾 (上) 网络上有很多乏味的编程题库,其中 Advent of code 近几年收到越来越多人的关注。起因是题目很乏味,联合圣诞节主题,在圣诞节前的25天每天一题。另外不限度编程语言,只须要输出正确答案即可。每做出一题还会失去一颗圣诞树上的小星星,有成就感。往年我应用 elixir 来解题,转眼间曾经做了过半的题目,于是写一篇文章来回顾一下。如果你也想尝试解题,倡议做完再看。 第一天第一局部是从一个由数字组成的列表中,找到两个数,它们的和等于2020,返回它们的积。 为了让查问快一些,我用了一个 MapSet (查问复杂度 O(1)) 来代替 List (查问复杂度O(n)) 存储这些数字,而后遍历 List,在 MapSet 中寻找可能和以后的数相加等于 2020 的数。 Enum.reduce_while(list, mapset, fn x, acc -> if MapSet.member?(acc, 2020 - x) do {:halt, x * (2020 - x)} else {:cont, MapSet.put(acc, x)} endend)第二局部是把两个数变成了三个数。能够三次遍历 List,而后应用 raise 语句来抛出异样从在找到满足条件的数时突破循环。因为题目规定不能够重复使用同一个地位的数,所以须要记录每个数的 index。 也能够应用三次嵌套的 reduce_while 来寻找答案,益处是不须要 raise 和 index 了,毛病是代码看起来很丑。 Enum.reduce_while(list, list, fn x, list -> case Enum.reduce_while(tl(list), tl(list), fn y, list -> case Enum.reduce_while(tl(list), tl(list), fn z, list -> if x + y + z == 2020 do {:halt, x * y * z} else {:cont, tl(list)} end end) do [] -> {:cont, tl(list)} a -> {:halt, a} end end) do [] -> {:cont, tl(list)} a -> {:halt, a} endend)第二天第一局部和第二局部都是依据既定的规定来统计非法的 “明码” 的数量,不同之处是应用的规定不同。第一局部的规定是字符串里某个字母呈现的次数,例如 1-2 z 示意字符串里只能由 1 到 2 个 z 。比拟麻烦的中央可能就是把规定解码进去,如果你相熟正则表达式会比拟快。而后依据规定查看每个 "password"。 ...

December 14, 2020 · 5 min · jiezi

关于elixir:Phoenix-集成-ejabberd

mix.exs 增加依赖{:ejabberd, "~> 20.4"}配置 ejabberd application config/config.exsconfig :ejabberd, file: "config/ejabberd.yml", log_path: 'logs/ejabberd.log'config :mnesia, dir: 'mnesiadb/'下载官网示例配置文件到 config/ejabberd.yml https://github.com/processone... 编译mix.deps get mix compileopenssl 问题===> /Users/lidashuang/Github/ejabberd/deps/fast_tls/c_src/fast_tls.c:21:10: fatal error: 'openssl/err.h' file not foundopenssl https://github.com/processone... 设置环境变量 export LDFLAGS="-L/usr/local/opt/openssl/lib"export CFLAGS="-I/usr/local/opt/openssl/include/"export CPPFLAGS="-I/usr/local/opt/openssl/include/"

November 23, 2020 · 1 min · jiezi

关于elixir:elixir-0067-保存-IEX-的历史记录

平时应用 iex 进行调试时常常会遇到须要从新关上 iex 的状况,这时候方才输出的历史内容就全副失落了。那么如何让 iex 保留历史记录呢? 只须要在你的 shell 的 profile 外面加上这一行(例如 bash 对应的 ~/.bash_profile 文件: export ERL_AFLAGS="-kernel shell_history enabled"source 之后,iex就会保留历史记录啦。默认的下限是 512kb,如果想要更多,把命令改成: export ERL_AFLAGS="-kernel shell_history enabled -kernel shell_history_file_bytes 1024000"就能够啦.

October 30, 2020 · 1 min · jiezi

关于elixir:elixir-0061-高负载高并发问题的万能钥匙-队列queue

高负载高并发问题,不仅仅呈现在面试中,在日常生活中也很常见,比方周末去冷落的商场吃饭,餐厅们口常常会须要排队取号。能够演绎为“需要”和“资源”的不匹配,多进去的“需要”的不到满足,就须要有适合的机制让这些”需要“进行 期待 或者 撤销。 让咱们用 elixir 模仿这样一个场景:一个服务器里一共有 3 个座位,每进来1个客人就要占用一个座位,座位占满之后服务器就无奈提供服务。 defmodule M5 do use GenServer @seats 3 @wait_timeout 1000 def start() do GenServer.start(__MODULE__, :ok) end def enter(pid) do GenServer.call(pid, :enter, @wait_timeout) end def leave(pid) do GenServer.cast(pid, :leave) end def init(_) do {:ok, @seats} end def handle_call(:enter, {_pid, _ref}, seats) do IO.puts("got enter request") if seats > 0 do {:reply, :ok, print(seats - 1)} else {:noreply, print(seats)} end end def handle_cast(:leave, seats) do IO.puts("free seats: #{seats}") {:noreply, print(seats + 1)} end defp print(seats) do IO.puts("free seats: #{seats}") seats endend再定义这样一个函数,模仿客人们同时要求进入服务器,如果得不到响应,就会 BOOM! ...

October 23, 2020 · 2 min · jiezi

关于elixir:elixir-0060-玩转外部资源-Port-入门

在 erlang 虚拟机中,port 是链接 process 的消息传递世界,与 erlang 虚拟机之外 linux 零碎世界的桥梁。在 process 看来,port是一种非凡的资源。 让咱们来看看在 elixir 中能够如何操作 port。 新建 portiex(5)> port = Port.open('computer', [])#Port<0.5>留神 port 的 name 因为历史起因须要应用 charlist. 新建胜利后会失去一个 port 的 id。 查看 port 信息iex(6)> Port.info port[ name: 'computer', links: [#PID<0.105.0>], id: 40, connected: #PID<0.105.0>, input: 0, output: 0, os_pid: :undefined]咱们看到一个 port 能够 link 到多个 porcess,这里的 link 机制和 process 之间的 link 机制是一样的,即 crash 会传导。 一个 port 同时只能 connect 到一个 process。connect 意味着 port 的所有音讯都会发送到这个 process. ...

October 23, 2020 · 1 min · jiezi

关于elixir:elixir-0059-Elixir-是如何获取到-doc-内容的

初学 elixir 时就被它不便的文档编写形式所吸引,咱们能够这样编写模块的文档和函数的文档: defmodule M4 do @moduledoc """ Module doc for M4. """ @doc "function doc for f" def f do endend能够在 repl 里间接查看,也能够生成网页版的文档。 iex(2)> h M4 M4 Module doc for M4.iex(3)> h M4.f def f() function doc for f那么 elixir 到底是如何从代码文件中获取到 doc 内容的呢。 Code.fetch_docs规范库的 Code 模块里自带了很多用于解决源文件的函数,其中 Code.fetch_docs 能够间接获取一个模块里全副的 doc 内容: iex(1)> Code.fetch_docs M4{:docs_v1, 2, :elixir, "text/markdown", %{"en" => "Module doc for M4.\n"}, %{}, [{{:function, :f, 0}, 6, ["f()"], %{"en" => "function doc for f"}, %{}}]}让咱们来看看它的外部实现: ...

October 21, 2020 · 2 min · jiezi

关于elixir:elixir-0058-使用macro为函数添加参数

有时咱们在批改程序的时候只是心愿给旧的函数增加一个参数,咱们能够应用macro来简化这一流程。 这里是一个简略的例子,咱们应用了一个名为 define 的宏,它的作用是增加一个名为 state 的参数到函数里。 defmodule M3 do use M2, head: :state define f(:a, a) define f(:b, b) define g(a, c)endiex(1)> h M3.f def f(state, atom, a) define 宏的实现是这样的: defmodule M2 do defmacro __using__(opts) do head = opts[:head] Module.put_attribute(__CALLER__.module, :__head__, head) quote do import M2 end end defmacro define(call) do case Macro.decompose_call(call) do {f, a} -> mod = __CALLER__.module var = Module.get_attribute(mod, :__head__) |> Macro.var(nil) args = [var | a] quote do def unquote(f)(unquote_splicing(args)) do IO.puts("args: #{inspect(unquote(args))}") end end _ -> raise "invalid args" end endend次要的几个点: ...

October 21, 2020 · 1 min · jiezi