Functions Tutorial, Part 2

You can download the source code for this tutorial here.

Case Statements

Let’s look at another function. This one has a new bit of syntax: a case statement.

fun getServiceUrlForRegion(region: AWS.Region) -> String:
  case region of
    | AWS.Ap-northeast-1 -> "https://12345678"
    | AWS.Ap-northeast-2 -> "https://23456789"
    | AWS.Ap-south-1     -> "https://34567890"
    | AWS.Ap-southeast-1 -> "https://76767676"
    | AWS.Ap-southeast-2 -> "https://88888888"
    | AWS.Eu-central-1   -> "https://42424242"
    | AWS.Eu-west-1      -> "https://00000000"
    | AWS.Sa-east-1      -> "https://22222222"
    | AWS.Us-east-1      -> "https://33333333"
    | AWS.Us-east-2      -> "https://44444444"
    | AWS.Us-west-1      -> "https://55555555"
    | AWS.Us-west-2      -> "https://66666666"
    | _                  -> "https://77777777"

We’ll zoom in on the first line again:

fun getServiceUrlForRegion(region: AWS.Region) -> String:

As before, fun indicates that this is a function, and it’s named getServiceUrlForRegion. This time, though, the function takes a parameter named region of the type AWS.Region and returns a String.

Let’s examine the body of the function.

case region of
  | AWS.Ap-northeast-1 -> "https://12345678"
  | AWS.Ap-northeast-2 -> "https://23456789"
  | AWS.Ap-south-1     -> "https://34567890"
  | AWS.Ap-southeast-1 -> "https://76767676"
  | AWS.Ap-southeast-2 -> "https://88888888"
  | AWS.Eu-central-1   -> "https://42424242"
  | AWS.Eu-west-1      -> "https://00000000"
  | AWS.Sa-east-1      -> "https://22222222"
  | AWS.Us-east-1      -> "https://33333333"
  | AWS.Us-east-2      -> "https://44444444"
  | AWS.Us-west-1      -> "https://55555555"
  | AWS.Us-west-2      -> "https://66666666"
  | _                  -> "https://77777777"

The case region of begins the case statement. Here, we’re saying, “in the case that region matches this constructor, return the corresponding expression.” So, if region equals AWS.Us-west-2, the function returns the string "https://66666666". This is called pattern matching. The _ in the last line represents the default case, acting as a catch-all that applies to “any value not listed above.” So, if region were to equal AWS.Eu-west-2, which is not listed, the function would return the string "https://77777777".

Note that region is a parameter to this function. You can put any kind of valid statement after case, such as another function call. This would be a perfectly valid (if pointlessly complex) case statement:

fun isOddWithCase() -> String:
  case isOdd(3) of
    | True  -> "Well of course."
    | False -> "In other news, 2+2=5."

So, to sum it all up, the function getServiceUrlForRegion takes an AWS.Region argument, pattern-matches based on the argument’s value, and returns a corresponding string. Essentially, the function returns a web service URL for any Fugue-supported AWS region, and it can be called like so:

printMyUrl: String.print(getServiceUrlForRegion(AWS.Us-west-2) ++ "\n")

The above line passes the results of getServiceUrlForRegion(AWS.Us-west-2) as the argument to the function String.print, which will print out the results, plus a newline (the "\n". You should see the output https://66666666 on your screen when you compile the module. Note that the result of String.print is bound to the name printMyUrl. The actual result of String.print isn’t important to us right now, but note that function application must always be on the right-hand side of a binding. If you don’t want to use the binding, you don’t have to, and you can name it something throwaway like void or main. Ludwig programs don’t have a traditional runtime, so the extra “variable” isn’t using any extra memory.

Here’s another example of a function using a case statement:

fun getNextLecture(fugueSkill: Int) -> String:
  case fugueSkill of
    | 1 -> "https://docs.fugue.co/ludwig-guide-functions-1.html"
    | 2 -> "https://docs.fugue.co/ludwig-guide-functions-2.html"
    | 3 -> "https://docs.fugue.co/ludwig-guide-functions-3.html"
    | 4 -> "https://docs.fugue.co/ludwig-guide-functions-4.html"
    | 5 -> "https://docs.fugue.co/ludwig-guide-functions-5.html"
    | 6 -> "https://docs.fugue.co/ludwig-guide-functions-6.html"
    | _ -> "https://docs.fugue.co"

The function is called with the following line:

printNextLecture: String.print(getNextLecture(3) ++ "\n")

When you download the file here and compile it using lwc FunctionTutorial2.lw, you’ll see output with the URL of the next page in the tutorial.

Exercise 2

Ready for your next exercise? Below is a function, but there’s something wrong with it. Find the mistake and fix it, so that the module compiles.

When fixed, the tagValueIsDevelop function takes an AWS.Tag argument and returns a Boolean value. If the value of a given tag is the string "Develop", the function returns True. If the value of the tag is anything else, the function returns False.

fun tagValueIsDevelop(tag: AWS.Tag) -> Bool:
  case AWS.Tag.value(tag) off
    | "Develop" -> True
    | _         -> False

Hint: If you try to compile the module as is, the compiler will give you a tip about what’s wrong.

You can download the file here. Compile it by executing the following:

lwc FunctionTutorial2.lw