gpt4 book ai didi

python - 在 Elixir 中寻求 "send+more=money"的惯用、优雅的解决方案

转载 作者:太空宇宙 更新时间:2023-11-03 13:40:44 25 4
gpt4 key购买 nike

我遇到了 Mark Dominus' blog post描述解决 "SEND+MORE=MONEY" puzzle在 Python 中使用函数式编程技术(特别是 Monads)。

此处总结了死链接情况下的难题:

    S E N D   | Find each character's *unique* numerical value, such that
+ M O R E | the addition on the left is valid. There are no leading zeros.
-----------
= M O N E Y

我一直在寻找机会学习一些纯函数式编程,特别是 Elixir,这似乎是一个非常合适的项目。

我可以在 Elixir 中实现 Mark Dominus 的 Python 代码的外观相似版本:

defmodule Smm do
def make_set(ls), do: Enum.into(ls, HashSet.new)

def to_number([]), do: :error
def to_number(ls), do: Enum.join(ls) |> Integer.parse |> elem(0)

def remove(hs, ls), do: Set.difference(hs, Enum.into(ls, HashSet.new))

def let(x, func), do: func.(x)

def guard(predicate, func) when predicate, do: func.()
def guard(predicate, func), do: []
end

digits = Smm.make_set(0..9)

Enum.map( Smm.remove(digits, [0]), fn s ->
Enum.map( Smm.remove(digits, [s]), fn e ->
Enum.map( Smm.remove(digits, [s,e]), fn n ->
Enum.map( Smm.remove(digits, [s,e,n]), fn d ->
Smm.let(Smm.to_number([s,e,n,d]), fn w_send ->
Enum.map( Smm.remove(digits, [0,s,e,n,d]), fn m ->
Enum.map( Smm.remove(digits, [s,e,n,d,m]), fn o ->
Enum.map( Smm.remove(digits, [s,e,n,d,m,o]), fn r ->
Smm.let(Smm.to_number([m,o,r,e]), fn w_more ->
Enum.map( Smm.remove(digits, [s,e,n,d,m,o,r]), fn y ->
Smm.let(Smm.to_number([m,o,n,e,y]), fn w_money ->
Smm.guard(w_send + w_more == w_money, fn ->
[w_send, w_more, w_money] |> Enum.map( &(IO.puts(&1)) )
end)end)end)end)end)end)end)end)end)end)end)end) # (╯°□°)╯︵ ┻━┻

但有些事情告诉我必须有一种方法来解决疯狂嵌套的匿名函数和随后的表格翻转;这就是纯函数式语言存在的原因,对吧?

看看 Mark Dominus 的 previous blog post in which he solves the puzzle with Haskell ,我看到他正在使用含糖版本的 Haskell 的“绑定(bind)”运算符 >>= 来消除翻 table 的冲动......但我没有 learned me a Haskell ,所以我对这篇博文中提供的代码没有很强的把握。

我相当确定我在 Elixir 实现中缺少的是使用管道运算符 |>,这对我来说实际上是这门语言的一大吸引力(对 Unix 非常熟悉管道,我自己)。我曾尝试在管道中工作并结合多种风格的 Enum.{map,reduce},但我总是回到原点。

有人可以提供任何建议吗?理想情况下,我正在为 Elixir 中的这个难题寻找更惯用的函数式编程解决方案。

最佳答案

您可以在这里查看:What is the "|>" symbol's purpose in Elixir? |> 运算符的概述。但基本思想是 a |> f(b, c)f(a, b, c) 相同。当你做类似 a |> f(b) |> g(c) 的事情时,这非常有用,根据上面的规则,它与 g(f(a, b) 相同, c),但读起来更漂亮。

话虽如此,|> 运算符(称为管道)不是单子(monad)绑定(bind) (>>=),并且不允许您“展平”深层嵌套循环就像 >>= 一样。对于在 Elixir 中看起来更好的任务替代方法,您可以:

  1. 使用实现 Monad 语法的库(或添加您自己的语法),例如 MonadEx
  2. 停止使用这种循环方法,例如使用递归函数预先生成数字到字母的分配,如下所示:

    defmodule Smm do
    # some more things

    def assignments(0, _), do: [[]]
    def assignments(n, digits \\ Enum.into(0..9, HashSet.new)) do
    digits
    |> Stream.flat_map(fn (d) ->
    for rest <- assignments(n - 1, Set.delete(digits, d)) do
    [d | rest]
    end
    end)
    end
    end

    for [s, e, n, d, m, o, r, y] <- Smm.assignments(8) do
    w_send = Smm.to_number([s, e, n, d])
    w_more = Smm.to_number([m, o, r, e])
    w_money = Smm.to_number([m, o, n, e, y])

    if s > 0 && m > 0 && (w_send + w_more == w_money) do
    IO.inspect([w_send, w_more, w_money])
    end
    end

关于python - 在 Elixir 中寻求 "send+more=money"的惯用、优雅的解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31823272/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com