【问题标题】:Why can't I aplly anonymous functions to lists?为什么我不能将匿名函数应用于列表?
【发布时间】:2021-05-13 04:18:24
【问题描述】:

所以我正在尝试学习 Elixir(我有 F# 和 Haskell 的背景),但我很难理解我的代码中发生了什么:

fizz_buzz = fn
  (0, 0, _) -> "FizzBuzz"
  (0, _, _) -> "Fizz"
  (_, 0, _) -> "Buzz"
  (_, _, c) -> c
end

fizz_buzz_rem = fn n -> fizz_buzz.(rem(n, 3), rem(n, 5), n) end


# This works
IO.puts(fizz_buzz_rem.(10))
IO.puts(fizz_buzz_rem.(11))
IO.puts(fizz_buzz_rem.(12))
IO.puts(fizz_buzz_rem.(13))
IO.puts(fizz_buzz_rem.(14))
IO.puts(fizz_buzz_rem.(15))
IO.puts(fizz_buzz_rem.(16))
IO.puts(fizz_buzz_rem.(17))

IO.puts("----------------")

inputs =
  10..17
  |> Enum.to_list

# Doesn't work
inputs
|> Enum.map(fizz_buzz_rem)
|> IO.puts

IO.puts("----------------")

# Doesn't work
inputs
|> Enum.map(fn n -> fizz_buzz.(rem(n, 3), rem(n, 5), n) end)
|> IO.puts

IO.puts("----------------")

manual_inputs = [10, 11, 12, 13, 14, 15, 16, 17]

# Doesn't work
manual_inputs
|> Enum.map(fizz_buzz_rem)
|> IO.puts

IO.puts("----------------")

# Doesn't work
manual_inputs
|> Enum.map(fn n -> fizz_buzz.(rem(n, 3), rem(n, 5), n) end)
|> IO.puts


IO.puts("----------------")

# The idiotic way (that doesn't work)

result = [
  fizz_buzz_rem.(10),
  fizz_buzz_rem.(11),
  fizz_buzz_rem.(12),
  fizz_buzz_rem.(13),
  fizz_buzz_rem.(14),
  fizz_buzz_rem.(15),
  fizz_buzz_rem.(16),
  fizz_buzz_rem.(17),
]

IO.puts result

# ???????????

当我运行elixir ex_02.exs 时,输出是:

Buzz
FizzBuzz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
----------------
Buzz
FizzBuzz
----------------
Buzz
FizzBuzz
----------------
Buzz
FizzBuzz
----------------
Buzz
FizzBuzz

所以你可以看到,当我将匿名函数分别应用于每个值时,我得到了正确的答案,但当我尝试使用范围、映射甚至手动将函数应用于列表的每个元素时,我最终得到了错误结果。

将匿名函数应用于 elixir 中的列表有什么问题?

【问题讨论】:

  • 试试inputs |> Enum.map(fizz_buzz_rem) |> Enum.map(&IO.puts/1)

标签: functional-programming elixir


【解决方案1】:

如果你使用IO.inspect而不是IO.puts,你可以看到发生了什么:

["Buzz", 11, "Fizz", 13, 14, "FizzBuzz", 16, 17]

您的 fizzbuzz 函数根据输入返回字符串或整数。 IO.puts 根据整数是否在列表中以不同方式处理整数:

iex(1)> IO.puts(65)
65
:ok
iex(2)> IO.puts([65])
A
:ok

所以在您的代码中,IO.puts 实际上打印了与整数 11、13、14、16 和 17 对应的控制代码。在我的终端中,它显示为:

Buzz^KFizz^M^NFizzBuzz^P^Q

你可以通过让你的函数总是返回字符串来解决这个问题:

fizz_buzz = fn
  (0, 0, _) -> "FizzBuzz"
  (0, _, _) -> "Fizz"
  (_, 0, _) -> "Buzz"
  (_, _, c) -> "#{c}"
end

【讨论】:

  • 这是意外地雷的另一个受害者,当 Elixir 将整数解释为 ASCII 代码点时可能会爆炸——在这种情况下,所有这些整数都映射到各种空格或控制字符,所以你不能看看发生了什么。查看类似的问题/答案,例如stackoverflow.com/questions/65794847/…
  • 这实际上是不同的东西,它在处理 IO 时非常很方便 - iovec 当您使用不可变语言工作并且需要构建大仅用于 IO 的字符串。
猜你喜欢
  • 2020-09-24
  • 1970-01-01
  • 2017-12-04
  • 2021-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多