Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Functional programming 如何在函数式编程语言中使用函数而不是早期返回_Functional Programming_Elixir - Fatal编程技术网

Functional programming 如何在函数式编程语言中使用函数而不是早期返回

Functional programming 如何在函数式编程语言中使用函数而不是早期返回,functional-programming,elixir,Functional Programming,Elixir,我最近开始学习,我真的很喜欢它,但它是我使用过的第一种函数式编程语言。我所面临的问题是,我一直在阅读教程并在上观看屏幕广播,你应该尽量避免使用IFtype语句 但我发现自己一直在嵌套cond或case 我会在其他语言(如Golang或Javascript)中解决这些解决方案,只需使用带有提前返回的if语句,这样超出该语句的代码就不会运行,这使我99%的时间不必通过检查假值并返回来嵌套条件 因此,在Elixir(或其他函数式编程语言)中,您如何在不使用嵌套和利用语言功能的情况下,以适当的方式编写以

我最近开始学习,我真的很喜欢它,但它是我使用过的第一种函数式编程语言。我所面临的问题是,我一直在阅读教程并在上观看屏幕广播,你应该尽量避免使用
IF
type语句

但我发现自己一直在嵌套
cond
case

我会在其他语言(如Golang或Javascript)中解决这些解决方案,只需使用带有提前返回的if语句,这样超出该语句的代码就不会运行,这使我99%的时间不必通过检查假值并返回来嵌套条件

因此,在
Elixir
(或其他函数式编程语言)中,您如何在不使用嵌套和利用语言功能的情况下,以适当的方式编写以下内容

def loginPost(conn, %{"user" => user_params}) do
    # Look for user in database
    query = from u in User,
      where: u.email == ^user_params["email"],
      select: [u.email, u.username, u.password]

    data = Repo.all(query)

    # Check to see if a user had been found
    case (length data) == 0 do
      true -> # No user was found, send an error message
        conn
        |> json(%{ success: false, errors: ["Wrong username or password"]})
      false -> # A user was found, compare password
        [[email, username, db_password]] = data
        case Comeonin.Bcrypt.checkpw(user_params["password"], db_password) do
          true -> # Password was correct, set session and return a json response
            conn
            |> put_session(:authenticated, true)
            |> put_session(:username, username)
            |> put_session(:email, email)
            |> json(%{success: true}) # Send json response and redirect on client side
          false -> # Password was incorrect, send an error message
            conn
            |> json(%{success: false, errors: ["Wrong username or password"]})
        end
    end
  end
end

一种方法是将
一起使用。您可以创建单独的函数,如下所示:

def authenticate(email, password) do
  with {:ok, user} <- find_user(email),
    {:ok, user} <- validate_password(user, password),
    {:ok, user} <- validate_preconditions(user)
  do: {:ok, user}
end

defp find_user(email) do
  # return {:ok, user} if user is found, return {:error, :user_not_found} otherwise
end

defp validate_password(user, password) do
  # return {:ok, user} if password is correct, return {:error, :invalid_password} otherwise
end

defp validate_preconditions(user) do
  # return {:ok, user} if user is not banned or whatever, return {:error, :cant_be_logged_in} otherwise
end
这个例子可能更好,但你明白了

您也可以从中阅读答案,函数式编程的好处(和限制)之一是所有函数都必须返回一个值。在类型化FP(例如F#、Scala、Haskell)中,函数的所有可能出口的返回类型必须相同。因此,我不能让一个函数在输入错误时返回false,而在输入正确时返回一个数字。如何处理这种情况

1.)使函数的返回类型成为某种元组。这是许多语言中的常见做法。Erlang有很多函数,当事情正常时返回
{:ok,value}
,当出现问题时返回
{:error,message}
(或类似的东西)。然后,在使用元组中的第二个元素之前,调用函数询问原子以确保它是
:ok
。这有点骇人听闻,但这并不是世界上最糟糕的事情

2.)您可以抛出异常。尽管这看起来有点极端,但如果有道理的话,没有特别好的理由避免这种做法

3.)您可以在输入上添加保护,以确保一开始不会收到错误的输入

例如,考虑这一点:

def max(a, b) when is_number(a) and is_number(b) do
当然,这可以防止我不小心用字母或数字以外的任何东西呼叫
max
。可以使用额外的防护装置进一步约束输入。这将再次消除提前退出的原因之一


我将这些作为解决这个问题的其他三种方法。我认为@JustMichael关于将
结构结合使用的建议也是一个好主意;为了完整起见,我添加了这些方法。

我更想知道为什么应该避免使用if。。。这根本没有意义。在任何语言中,分支都是程序的组成部分。在一个非平凡的程序中,一定有一些分支发生了。@Hustmphrr我在Elixir的IRC/Slack上与一些人交谈过,他们通常会说,如果我太嵌套了,我想我在一个函数中做的太多了,只会编写另一个函数,这是另外一回事。它适用于所有语言,即避免过多嵌套结构。在fp中,没有循环结构,因此批评者都会指向分支。我明白这一点。更多的是关于模块化。不仅仅是为了避免某些特定的结构。我认为如果使用
这个代码会更好。@hustmphrr By code你是指上面给出的例子吗?是的。布尔值上的模式匹配很奇怪。但匹配一组布尔值是一种常见(也是很好)的做法。
def max(a, b) when is_number(a) and is_number(b) do