مشکل در درک قطعه کد elixir

درود خدمت دوستان

در حال ترجمه کتاب elixir بودم که با این کد برخورد کردم و برام الان قابل درک نیست البته چندجایی که در ادامه می گم :

people = [
  %{ name: "Grumpy",    height: 1.24 },
  %{ name: "Dave",      height: 1.88 },
  %{ name: "Dopey",     height: 1.32 },
  %{ name: "Shaquille", height: 2.16 },
  %{ name: "Sneezy",    height: 1.28 }
]

defmodule HotelRoom do

  def book(%{name: name, height: height})
  when height > 1.9 do
    IO.puts "Need extra long bed for #{name}"
  end

  def book(%{name: name, height: height})
  when height < 1.3 do
    IO.puts "Need low shower controls for #{name}"
  end

  def book(person) do
    IO.puts "Need regular bed for #{person.name}"
  end

end

people |> Enum.each(&HotelRoom.book/1)

#   Need low shower controls for Grumpy
#   Need regular bed for Dave
#   Need regular bed for Dopey
#   Need extra long bed for Shaquille
#   Need low shower controls for Sneezy 

خوب برام سواله چطور تمام فانکشن ها دو آرگومنت داره ولی این داره به صورت تک آرگومنت اطلاعات رو به داخلش ایمپورت می کنه

people |> Enum.each(&HotelRoom.book/1)

و چرا اول کلاس در خط بالا نوشته & چه معنی می ده مگه نباید مستقیم فراخوانی می کرد و همینطور /1 آخرش به صورت کلی خط آخر رو که اصل موضوع هست را درک نکردم اگر دوستان به بنده توضیح بدند واقعا ممنون می شم و همینطور می تونم توضیحات بهتری برای کتاب درج کنم

به به صورت مثال /1 احتمال داده که با یک آرگومانت وارد تابع بشه چون تمام داداه ها داخل متغییر هست ولی & اول قالب درک نیست برام چون بدون اون کار نمی کنه

تشکر :bouquet:

Enum.each(people, fn(x) -> HotelRoom.book(x) end)
این معادل 
people |> Enum.each(&HotelRoom.book/1)

هستش.
<|
یا پایپ نتیجه قسمت چپ به عنوان اینپوت اول سمت راست وارد میکنه

"Hi" |> IO.puts
IO.puts "Hi"

& یک سینتکس که بهش میگن capture operator
اگر یک ارگومنت به anonymous function میخواهید بدید بجای نوشتن
میتونید از capture operator استفاده کنید
1/
نشانگر arity هست arity یعنی تعداد ارگومنت یک فانکشن میگیره اگر فانکشن دو ارگومنت میگیره arity ۲داره دلیل وجود این نشانه به دلیل وجود pattern matching در الیکسیر که یک فانکشن میتونه با Arity مختلف بدنه مختلف داشته باشه
Capture operator همیشه به arity نیاز داره

2 پسندیده

تشکر می کنم . واقعا ممنونم . من هرچی می خواستم ببنیم fn چطور می تونه تو بالا بزاره که معادلش بشه کدی که خودش قرار دادن فکرم یاری نمی کرد . این قسمت به کتاب با اجازتون اضافه می کنم
تشکر

خواهش میکنم

1 پسندیده

سلام، من هيچ فانكشنى در مثال شما نديدم كه دو تا ارگومان دريافت كنه

1 پسندیده

درود . اشتباه از بنده بوده در چندین جا یکی از موارد شما فرمودید من فکر کردم مپ من که دوتا بود . فکر کردم دوتا آرگومنت دارم . ولی در کل یکی هست
تشکر

1 پسندیده

درود خدمت دوستان مثل اینکه من تو این بخش بسیار ضعف دارم :frowning:

کد زیر رو ببنید

validate_change(:date, &must_be_future/2)

می خوام تبدیل کنیم به fn به صورت زیر ارور دارم

validate_change(:date, fn(x) -> must_be_future(x) end) 

تابع دوتا آرگومنت داره ولی من دارم بهش یک آرگومنت می دم . بخاطر همین ارور دارم چندین روش دیگه زدم . مثل اینکه هنوز درک نکردمش

من این کارو کردم

|> validate_change(:date, fn(s, x) -> must_be_future(s,x) end)  

ارور رفع شد . تابع اصلی من اینه

defp must_be_future(_ , value) do
		Ecto.DateTime.compare(value, Ecto.DateTime.utc)
		|> get_error
	end

	defp get_error(comparison) when comparison == :lt do
		[date: "cant be in the past"]
	end

به نظرتون درست انجام دادم ؟

تستی که انجام می دم کد مشکلی نداره و کار می کنه و یک سوال هم در این رابطه دارم چرا برای بررسی زمان اومده دوتا آرگومنت به must_be_future داده ؟
تگ آرگومنت ارور می ده و می گه شما می خواهید یک آرگومنت را در دو آرگومنت بزارید دلیل درخواست دو آرگومنت هم من متوجه نشدم . مثل اینکه php مغز مارو قفل کرده

سلام، ببخشيد كه بريده بريده ميام،
چنتا مشكل هست، اول اينكه خود اصل ارور رو قرار بدين.
و دوم اين كه چرا در قسمت error, پيام خطا با date: نشانه گزارى شده؟ و چرا از keyword list استفاده شده؟
از اسم متد get_error اينطور به نظر مياد كه انگار خيلى جنراله اما اصلا اينطور نيست، شايد اصلا نيازى نباشه كه وجود داشته باشه.
شايد پاسخ به اين سوالات به من كمك كنه كه بهتر بتونم راهنمايى كنم

در مورد php هم بايد بگم كه ميتونه خيلى فانكشنال باشه و اصلا زبان بدى نيست، هرچند مثل همه زبان ها ضعف هاى زيادى داره

1 پسندیده

درود خدمت شما . تشکر از اینکه وقت می زارید و پاسخ بنده رو در انجمن قرار می دید یک دنیا ارزش داره تشکر

اول کل کد کوتاه این بخش رو قرار بدم شاید بهتر باشه :

defmodule Rsvp.Events do
	use Ecto.Schema
	import Ecto.Changeset

	schema "events" do
		field :title, :string
		field :location, :string
		field :date, Ecto.DateTime
		field :description, :string
		timestamps()
	end

	# @required_fields ~w(title location date)a
    # @optional_fields ~w(description)a


 	@required_fields [:title,:location,:date]
  	@optional_fields [:description]

	def changeset(event, params \\ %{}) do
		event
		|> cast(params, @required_fields ++ @optional_fields)
		|> validate_required(@required_fields)
		|> validate_change(:date, fn(s, x) -> must_be_future(s,x) end)  
	end
		# validate_change(:date, &must_be_future/2)
	defp must_be_future(_ , value) do
		Ecto.DateTime.compare(value, Ecto.DateTime.utc)
		|> get_error
	end

	defp get_error(comparison) when comparison == :lt do
		[date: "cant be in the past"]
	end

	defp get_error(_), do: []
end

من سوالاتی که شما گفتید رو نمی دونم . من دارم از یک ویدیویی که اموزش فونیکس هست این کد هارو می بینیم و می زنم و همینطور سعی دارم که تحلیل کنم چرا نوشته . خیلی بخش هاش مشکلی نیست ولی روندی که اینجا استفاده کرده برام جالب بوده

کلا ایشون می خواست بگه اگر تاریخ گذشته بود ارور بده حتما تاریخ امروز باشه که اومد فانکشن must_be_future رو نوشت که این فانکشن رو در ترمینال تست کردم چون اولین بار بود می بینمش . کامپر می کنه و یک جواب lt بر می گردونه اگر گذشته باشه و در تابع دیگه گفته اگر بود ارور بده get_error

من فقط نفهمیدم چرا اینجا باید

defp must_be_future(_ , value) do
		Ecto.DateTime.compare(value, Ecto.DateTime.utc)
		|> get_error
	end

دوتا ورودی بگیره و ورودی اول هم در نظر گرفته نشه . به ولیو باید از دیتابیس بیاد date رو بده و اون DateTime.utc که فکر کنم تاریخ الان رو نشون می ده که کامپر می کنه و lt قرار می ده در صورت false بودن و ارور چاپ می شه

و این بخش

|> validate_change(:date, fn(s, x) -> must_be_future(s,x) end)

کد های بالا :

must_be_future باید یک ارگومنت بگیره دو ارگومنت بی معنی چون در بدنه ارگومنت اول کاری باهاش نداره و _ گذاشته

1 پسندیده

درود من اومدم این خط هارو تغییر دادم

|> validate_change(:date, fn(x) -> must_be_future(x) end)  

و

defp must_be_future(value) do
	Ecto.DateTime.compare(value, Ecto.DateTime.utc)
	|> get_error
end

که کلا یک ورودی بگیره ولی ارور زیر رو دارم :

** (BadArityError) #Function<1.43260248/1 in Rsvp.Events.changeset/2> with arity 1 called with 2 arguments (:date, #Ecto.DateTime<2018-05-02 00:00:00>)
    (ecto) lib/ecto/changeset.ex:1236: Ecto.Changeset.validate_change/3

البته در زمانی که خط زیر رو برای تست چنج ست می زنم ( در iex )

Rsvp.Events.changeset(%Rsvp.Events{}, %{title: "swift3", location: "amol", date: "2018-05-02 00:00:00"})

validate_change هم عوض کنید
(validate_change(:date, fn(x) -> must_be_future(x) end

یعنی چطور بنویسیمش اینو تغییر دادم به شکل زیر شده

|> validate_change(:date, fn(x) -> must_be_future(x) end)

:thinking: یعنی چطور بنویسمش ؟

1 پسندیده

دادا خوب راه افتادی ها حال کردم ای کاش وقت بشه منم ‍‍میتونستم یاد بگیرم

1 پسندیده

نه بابا کجا راه افتادم هنوز مشکلم با کد بالا حل نشده. نمی دونم چرا ! داره دوتا ورودی می گیره در صورتی که منطقی نیست دوتا ورودی و فانکشن رو هم نتونستم تنظیم کنم یک دونه ورودی بفرسته

دو دوست خوبمون اگر وقت کردند کمک کنند این قسمت حل بشه واقعا لطف می کنند در حق بنده . خیلی تغییر دادم حل نشد
@samdvr
@toomaj

1 پسندیده

سلام، ببخشيد من كلا از زمينه بحث درو شدم، اگه ميشه كد هها رو يه جايى بزار كه چك كنم، اگر كيشه ارور هاى مربوط رو هم بزار

2 پسندیده

اون بالا هست، ببخشيد

2 پسندیده

درود تشکر از اینکه پاسخ دادید

ببنید این خط رو :

در خط ۲۷ نمی دونم چرا در ویدیو گفته دوتا ورودی بگیره . در صورتی یک ورودی رو حتی اسکیپ کرده

من بالا طبق صحبت دوست خوبمون @samdvr اومدم

|> validate_change(:date, fn(s, x) -> must_be_future(s,x) end)  

رو تبدیل کردم به

|> validate_change(:date, fn(x) -> must_be_future(x) end)

و همینطور فانکشن خط ۲۷ رو یک آرگومنت کردم بازم مشکل دارم و می گه آرگومنت شما دوتا پارامتر می خواد ولی شما یکی دارید می دید. . ارور هم در پست بالا قرار دادم . بازم تشکر

1 پسندیده

دو مشکل که درست کردم یکی اینکه validate_change 3 ارگومنت میگیره و validator در change_validate حتما باید. ارگومنت با دو Arity باشه

https://hexdocs.pm/ecto/Ecto.Changeset.html#validate_change/3
به همین دلیل پست اصلی دوتا ارگومنت برا validator گذاشته ولی در implementation استفاده نمیکنه از ارگومنت اول
دوم اینکه DateTime.compare باید دو تا DateTime تایپ و با هم مقایسه کنه و من Date تبدیل میکنم به DateTime قبل مقایسه

2 پسندیده

تشکر از شما ( خیلی ممنونم :rose: ) . پس خود ویدیو در اول همان کار کد هایی که قرار داده مشکلی نداره و منطق به همین طریق بوده که شما دوباره گفتیدش

فقط شما در قسمت تاریخ تغییر دادید و موردی که در کامپر بوده رو نیز از فانکشن from_date استفاده کردید . فکر کنم درست گفتم

تشکر

2 پسندیده