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

Dat*_*sik 2 functional-programming elixir

我最近开始学习Elixir,我真的非常喜欢它,但它是我用过的第一种函数式编程语言.我遇到的问题来自于我一直在阅读教程和在LearnElixir上观看截屏视频,你应该尽量避免使用IF类型语句.

但我发现自己经常筑巢condcase

我会用Golang或Javascript之类的其他语言解决这些解决方案,只需使用带有早期返回的if语句,这样超出该范围的代码就不会运行,这使得我不得不通过检查falsy来占用条件的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
Run Code Online (Sandbox Code Playgroud)

NoD*_*ame 7

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

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
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的控制器功能中使用它,如下所示:

def loginPost(conn, %{"user" => user_params}) do
  case authenticate(user_params["email"], user_params["password"]) do
    {:ok, user} -> # start session
    {:error, error_type} -> # handle error
  end
end
Run Code Online (Sandbox Code Playgroud)

这个例子可能会更好,但你明白了.

你也可以从这个问题中读出答案