Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Typespec Drills

exercises/typespec_drills.livemd

Typespec Drills

Mix.install([
  {:jason, "~> 1.4"},
  {:kino, "~> 0.9", override: true},
  {:youtube, github: "brooklinjazz/youtube"},
  {:hidden_cell, github: "brooklinjazz/hidden_cell"}
])

Navigation

Home Report An Issue Documentation And Static AnalysisGames: Documentation And Static Analysis

Typespec Drills

Drills help you develop familiarity and muscle memory with syntax through repeated exercises. Unlike usual problems, Drills are not intended to develop problem solving skills, they are purely for developing comfort and speed.

This set of drills is for typespecs. Follow the instructions for each drill and complete them as quickly as you can.

Review

You can define a function spec using the @spec module attribute. Each @spec includes the function parameter types, and the return value type.

@spec add(integer(), integer()) :: integer()
def add(int1, int2) do
  int1 + int2
end

You can define custom types using the @type module attribute. These custom types can be used inside and outside of the current module.

@type user :: %{
  name: string(),
  age: integer()
}

You can include multiple types using the | operator. This works for functions using @spec and in custom types.

@spec double(integer() | nil)

Function Specs

Add function @specs based on the function parameter names and return value.

Example Solution

defmodule FunctionSpecs do
  @spec do_nothing :: nil
  def do_nothing do
    nil
  end

  @spec accept_and_return_anything(any()) :: any()
  def accept_and_return_anything(anything) do
    anything
  end

  @spec double(float()) :: float()
  def double(float) when is_float(float) do
    float * 2.0
  end

  @spec double(integer()) :: integer()
  def double(integer) when is_integer(integer) do
    integer * 2
  end

  @spec double(number()) :: number()
  def double(number) do
    number * 2
  end

  @spec add(integer(), integer()) :: integer()
  def add(integer1, integer2) do
    integer1 + integer2
  end

  @spec multiply(integer(), integer()) :: integer()
  def multiply(integer1, integer2) do
    integer1 * integer2
  end

  @spec divide(integer(), integer()) :: float()
  def divide(integer1, integer2) do
    integer1 / integer2
  end

  @spec rounded_divide(integer(), integer()) :: integer()
  def rounded_divide(integer1, integer2) do
    div(integer1, integer2)
  end

  @spec concat(String.t(), String.t()) :: String.t()
  def concat(string1, string2) do
    string1 <> string2
  end

  @spec to_string(integer()) :: String.t()
  def to_string(integer) do
    Integer.to_string(integer)
  end

  @spec merge(map(), map()) :: map()
  def merge(map1, map2) do
    Map.merge(map1, map2)
  end

  @spec split_and_lowercase(String.t()) :: [String.t()]
  def split_and_lowercase(string) do
    string
    |> String.downcase()
    |> String.split("", trim: true)
  end

  @spec string_to_int(String.t()) :: integer()
  def string_to_int(string) do
    String.to_integer(string)
  end

  @spec integers_to_strings([integer()]) :: [String.t()]
  def integers_to_strings(integers) do
    Enum.map(integers, fn int -> Integer.to_string(int) end)
  end
  
  @spec one_to_two(1) :: 2
  def one_to_two(1) do
    2
  end
end
defmodule FunctionSpecs do
  def do_nothing do
    nil
  end

  def accept_and_return_anything(anything) do
    anything
  end

  def double(float) when is_float(float) do
    float * 2.0
  end

  def double(integer) when is_integer(integer) do
    integer * 2
  end

  def double(number) do
    number * 2
  end

  def add(integer1, integer2) do
    integer1 + integer2
  end

  def multiply(integer1, integer2) do
    integer1 * integer2
  end

  def divide(integer1, integer2) do
    integer1 / integer2
  end

  def rounded_divide(integer1, integer2) do
    div(integer1, integer2)
  end

  def concat(string1, string2) do
    string1 <> string2
  end

  def to_string(integer) do
    Integer.to_string(integer)
  end

  def merge(map1, map2) do
    Map.merge(map1, map2)
  end

  def split_and_lowercase(string) do
    string
    |> String.downcase()
    |> String.split("", trim: true)
  end

  def string_to_int(string) do
    String.to_integer(string)
  end

  def integers_to_strings(integers) do
    Enum.map(integers, fn int -> Integer.to_string(int) end)
  end

  def one_to_two(1) do
    2
  end
end

Custom Types

Implement the following custom @types in the module below based on the comment describing them.

Example Solution

defmodule CustomTypes do
  # a string or number
  @type unparsed_number :: String.t() | number()
  # a list of strings
  @type strings :: [String.t()]
  # a map with :title (string) and :content (string) keys. 
  @type book :: %{title: String.t(), content: String.t()}
  # A map with :name (string) and `:books` (a list of books) keys.
  @type author :: %{name: String.t(), books: [book()]}
end
defmodule CustomTypes do
  # a string or number
  @type unparsed_number
  # a list of strings
  @type strings
  # a map with :title (string) and :content (string) keys. 
  @type book
  # A map with :name (string) and `:books` (a list of books) keys.
  @type author
end

Commit Your Progress

DockYard Academy now recommends you use the latest Release rather than forking or cloning our repository.

Run git status to ensure there are no undesirable changes. Then run the following in your command line from the curriculum folder to commit your progress.

$ git add .
$ git commit -m "finish Typespec Drills exercise"
$ git push

We’re proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.

We also offer a paid course where you can learn from an instructor alongside a cohort of your peers. We will accept applications for the June-August 2023 cohort soon.

Navigation

Home Report An Issue Documentation And Static AnalysisGames: Documentation And Static Analysis