Hot answers tagged

11

I would like to slightly rewrite the problem before making it continuation based because it will make it clearer and avoid duplication: defmodule BTree do defstruct tree: nil def new(e), do: %BTree{tree: {e, nil, nil}} def insert(%BTree{tree: root}, element) do %BTree{tree: do_insert(root, element)} end defp do_insert(nil, element) do {...


9

The use-case you came up with looks like a very clear candidate to be a GenServer. A GenServer implementation will eliminate your need to manage the serving process, and using its client-side API conventions will also simplify the client usage. Here is a sample implementation of a fizzbuzz: defmodule FizzBuzz do use GenServer @fizz_buzz 15 @...


7

Your code looks very nice indeed, I only have some minor observations you code use to improve this code: Naming Use the imperative form of the verb (convert instead of converts) Implementation Hiding Use defp for methods which are not intended for external use. You might consider also renaming them to start with underscore _ to further differentiate them ...


6

Tail Recursion Erlang (and hence Elixir) pride in the tail recursion idioms they use. You've got one recursion in your code but it is not a tail recursion! This means that the recursive part is not the last thing in the function, and the tail recursion optimization cannot be used. Although your code's recursion is limited to up to 11 hits, it still misses ...


6

Using the ? for a boolean predicate is fine. At least it is what I would do in Ruby and Elixir. You won't be able to call exists?(env) in a guard clause so pattern matching does not win you much here. You are calling :os.getenv() twice unneccessarily. I'm not sure why you just want to convert 'false' to 'nil', here is a way: defmodule Envvar do def get(...


5

The mechanical usage of the struct seems correct, but I'm having some conceptual issues with the original code. First, the Stack structure models a single element instead of the entire structure. I find this weird, and it makes it impossible to implement custom protocols for the stack abstraction. Your module seems to partially abstract stack elements, and ...


5

I'm not sure why you'd need to pipe three different streams - one for every manipulation. I'd probably use one Stream to do all the manipulations together, something like: filedates = files |> Stream.map &((&1 |> File.stat!).ctime |> datastr.()) or filedates = files |> Stream.map &(File.stat!(&1).ctime |> datastr.())


5

It can be done several ways. Instead of explicitly using recursion we can, as @alxndr suggested, make use of the recursion capabilities of the Enum module. I am going to use Enum.map_reduce simply because I find it useful when troubleshooting to key the items and the accumulator in that form. In general the solution is the same as yours. def sum(list) ...


5

First of all, I agree with José about practical benefits. I would never aim for tail recursion in this example because: it reads much harder there are almost no benefits That being said, here's my take on making this function tail-recursive. It's not based on continuation, and I didn't clean up the structs (though I agree with José on this): defmodule ...


5

I'm probably no better in Elixir than you are, but I will give it a go. First of all the good parts: I think the function does what it should, and it's fairly neat. Not bad for a language that doesn't even have a concept of date, huh? :-) Suggestions for improvement: You should have a @doc attribute and unit tests :-) Remember to document that the range ...


5

Since you seem to know what the file extension is, you can use Path.basename/2. "foo.html.eex" |> Path.basename(".eex") |> IO.puts If you don’t know the file extension, you can use Path.extname/1 in conjunction. filename = "foo.html.eex" filename |> Path.basename(Path.extname(filename)) |> IO.puts


3

You can do this with an anonymous function Enum.reduce(lines, %{}, fn(line, result) -> String.split(line, ": ") |> (fn(x) -> Map.put(result, hd(x), List.last(x)) end).() end) You can also do it like this Enum.reduce(lines, [], fn(line, result) -> result ++ String.split(line, ": ") end) |> Enum.chunk(2) |> Map.new(fn [k, v] ->...


3

So, the only major comment I'd have on your code is that it's a bit hard to understand what's going on. It becomes a lot easier when you have the Kata text to help, but ideally the code itself should be quite easy to understand just by looking at it. I would split your code up into the seperate stages, rather than having a single function that does ...


3

When you end up with a pyramid of if-else clauses like this, it's sometimes a good idea to use cond instead. cond lets you specify a bunch of clauses, and picks the first one that matches. For example: def valid_phone(changeset, field) do phone = get_field(changeset, field) cond do phone == nil -> changeset String.length(phone) != 10 ...


3

You could cut out some of those intermediate variables using the pipeline operator: |> def age_post(post) do birthday = Timex.date({post.birthday_year, post.birthday_month, post.birthday_day}) (Date.now |> Timex.diff(birthday, :years) |> Integer.to_string) <> " ans" end


3

I've just taken a whack at cleaning up my original code after a few days. edit: Now including refactor suggestions from alxndr. Set everything in motion def run(job) do HTTPStatusCheck.run(job) |> update_db |> send_alerts end (The new run method seen here handles what was previously done by query and parse.) The new HTTPStatusCheck....


3

First: I have to admit, I do not know a single line Elixir. But on the other hand, I think I get, what the code does. I can not give you advice, how to implement the improvements, but I hope to help you anyway. In the description you have the following definition: single minutes: When it is 1 minute past the hour, YOOO is returned. When it is 2 ...


3

I think you're sort of missing the point with this code - the difference between different kinds of monads (Maybe vs. List vs. Identity, etc.) is in the different implementations of return and bind. I think a good starting place might be reading through a library that implements monads in elixir, like monad. Looking into that you can see that for example ...


3

Is it necessary to return nil or is false enough? They both evaluate to false when using boolean operators. If false is good enough: defmodule Envvar do def get(env) do {:env, :os.getenv(env)} end end If the return value has to be nil, I would just convert the second element and leave the first one intact. defmodule Envvar do def get(env) do ...


3

I think it is a perfect fit for with. It will be something like: def find_or_create_user(attrs \\ %{}) do with true <- String.ends_with?(attrs.email, "@test.com"), nil <- Repo.get_by(User, %{email: attrs.email}), {:ok, user} <- create_user(attrs) do {:ok, user} else false -> {:error, :invalid_email_domain} %...


2

José - Looking at it again, I see what you are saying about the init function to initiate a clean stack. I was thinking of this as an autonomous example and the init function just seemed superfluous. I was just trying to get away from the sense of state but being more of a pseudo gen_server example, the function fits. The binding also seemed excessive but ...


2

Keep in mind there is no reason to call init. Any state is being maintained outside the module. Also you can use recursion to iterate over the list. I don't typically use accumulators but in this case it seemed to fit. I also rely heavily on pattern matching. The EVM was designed with pattern matching optimization in mind so there isn't any drawback. Plus, ...


2

Overview I see that there are some good comments and I thought I'd just explain in a full answer block -- I'm not on here too often so I apologize for the tardiness of the response. Bear with me as I first show you what I might really do then demonstrate the answer to your tail recursive question using the same terms with which you posed your question. ...


2

Extracting helper functions to add data to the return value means you can move the guard clauses to the helper functions, which seems to clarify the causes and effects happening here, and also will shorten the function signatures. Untested code: def parse(%HTTPCheckResult{parsed: false, http_response: {:ok, %Response{status_code: c}}} = check_result) do ...


2

Just finished that exercise too. I think you can extract some of that logic to anonymous functions. It isolates a pieces of behaviour that you can work on. defmodule Words do @doc """ Count the number of words in the sentence. Words are compared case-insensitively. """ @spec count(String.t) :: map def count(sentence) do filter_word = fn(...


2

Personally I would do the inc and count of the attempts in one place, You can still split it, but you actually need this every time an attempt is going to happen. You could also replace the if with a case. You don't have to, but I think it looks nicer :) The next thing is, remove the when password == @password_login and just use @password_login in the ...


2

This would also be solvable with a map instead of a reduce lines |> Enum.map(&String.split(&1, ": ")) |> Map.new(&List.to_tuple/1)


2

You've implemented it by pattern matching against empty lists with def main([]). If an empty list is passed to main, it will be caught here. In the second def main(args), args should never be an empty list. If you want to make sure that args is a list, you could use a guard clause: def main(args) when is_list(args). (You should then write a catch-all third ...


2

You could use a map to store the pairs with their first occurrence while iterating over the pairs. Break if the current pair was already found at a position less than the current position minus 1. def has_non_overlapping_pair(string) do 0..String.length(string) - 2 |> Enum.reduce_while(%{}, fn n, m -> pair = String.slice(string, n, 2) pos ...


2

Yes, using ETS for this sort of temporary data is totally fine, as long as you realize of course that all that intermediate state is lost whenever you restart your server. In fact, if you dig into Phoenix and Elixir a bit, you will see a lot of ETS usage - it's not so much a thing you turn to in exceptional circumstances, but more a tool in the extensive ...


Only top voted, non community-wiki answers of a minimum length are eligible