Conditional Expressions in the Alexa Conversations Description Language (ACDL)

In the Alexa Conversations Description Language (ACDL), you can use conditional expressions to create branches in the conversational flow that your dialog samples describe. Conditional expressions reduce the need to write variations of a conversational flow that differ only based on some conditional logic. With conditional expressions, samples can describe multiple desired flows for conversational experiences.

Syntax

Conditional expressions follow an if, else if, and else chaining syntax. The expression in the condition must be of type com.amazon.alexa.schema.Boolean. The if, else if, and else follow the expression block syntax, type, and name-scoping rules. The types of all the expression blocks in the same conditional expression must match.

conditionalExpr
    : IF LPAREN expression RPAREN blockExpression (ELSE (conditionalExpr | blockExpression))
    ;

The following is the minimum possible conditional expression. Every conditional expression must have an else block.

if (<condition>)
  <expression-block>
else
  <expression-block>

A conditional expression can have zero or more else if conditions as follows.

if (<condition>)
  <expression-block>
else if (<condition>)
  <expression-block>
else
  <expression-block>

You can nest conditional expressions as follows.

if (<condition>)
  <expression-block>?

    if (<condition>)
      <expression-block>
    else
      <expression-block>

    <expression-block>?

else
  <expression-block>

Example

An example use case for conditional expressions is to specify the response Alexa gives in conditions such as failure or success. In the following example, the response in the conversational flow differs depending on whether the getWeather() action returns a forecast versus nothing.

sample {
  weatherRequest = expect(Invoke, getWeatherEvent)

  ensure(
    RequestArguments {arguments = [getWeather.arguments.cityName], response = request_city_prompt},
    RequestArguments {arguments = [getWeather.arguments.date], response = request_date_prompt}
  )

  weatherResult = getWeather(weatherRequest.cityName, weatherRequest.date)

  if (weatherResult != nothing) {
    response(weather_prompt, Notify {actionName = getWeather, success = true}, payload = WeatherResultPayload {weatherResult = weatherResult})
  } else {
    response(bye_prompt, Bye {})
  }
}

Restrictions on conditional expressions

  • All conditional expressions must have an else block, and the else block must not be empty. That is, the else block must contain expressions.

  • Every block expression in a conditional expression must contain a response() action.

  • The Boolean expression in the condition must reference at least one result from a previous external action invocation and can only reference names from the previous external action invocations.

    The following example shows an invalid conditional expression.

    // An invalid example
    sample {
    bookFlightRequest = expect(Invoke, BookFlightEvent)
    ensure(
      RequestArguments {arguments = [searchFlights.arguments.fromCity], response = fromCityPrompt},
      RequestArguments {arguments = [searchFlights.arguments.toCity], response = toCityPrompt},
      RequestArguments {arguments = [searchFlights.arguments.startDate], response = startDatePrompt}
    )
    searchResult = searchFlights(bookFlightRequest.fromCity, bookFlightRequest.toCity,
                  bookFlightRequest.startDate)
    
    // This is invalid because the name used in the condition's boolean expression refers to a name that does not result from a previous API invocation. It refers to a name from an expect() action call.
    if (bookFlightRequest != nothing) {
      ...
    } else {
      ...
    }
    }
    
  • Either a response() action or another conditional expression must come before any external (user-defined) action invocation or event in a conditional block expression.

    The following examples contain valid conditional expressions.

    if (condition) {
     payload = SearchResultPayload {result = searchResult}
     act = Notify {actionName = searchFlights}
    
     // Alexa response or another conditional expression must come before the next external action invocation or event expression
     response(informBookingResponse, act, payload)
    } else {
     ...
    }
    
    if (condition) {
     payload = SearchResultPayload {result = searchResult}
     act = Notify {actionName = searchFlights}
    
     // Another conditional expression can come before the first Alexa Response
     if (anotherCondition) {
       response(informBookingResponse, act, payload)
     } else {
       ...
     }
    } else {
     ...
    }
    
    if (condition) {
     // This is allowed because it is a natively supported action, not an external action
     x = size(list)
     ...
    } else {
     ...
    }
    

    The following example shows an invalid conditional expression that violates this rule.

    // An invalid example
      if (condition) {
          // This is invalid because an event expression comes before the response()
          flightDetail = expect(Inform, InformOrdinalEvent)
          confirmAction(confirmFlightBooking, bookFlight, SearchResultPayload {searchResult = searchResult})
          expect(Affirm, affirmEvent)
          bookingDetail0 = bookFlight(searchResult, flightDetail.ordinal)
          response(informBookingResponse, Notify {actionName = bookFlight, success = true}, payload = BookingDetailPayload {itinerary = bookingDetail0})
      } else {
          ...
      }
    
  • The first response act in a conditional block expression must be the Notify response act. This rule includes response() actions that chain Notify with additional response acts.

    // An invalid example
    sample {
    bookFlightRequest = expect(Invoke, BookFlightEvent)
    ensure(
      RequestArguments {arguments = [searchFlights.arguments.fromCity], response = fromCityPrompt},
      RequestArguments {arguments = [searchFlights.arguments.toCity], response = toCityPrompt},
      RequestArguments {arguments = [searchFlights.arguments.startDate], response = startDatePrompt}
    )
    searchResult = searchFlights(bookFlightRequest.fromCity, bookFlightRequest.toCity,
                  bookFlightRequest.startDate)
    if (searchResult.status == "success") {
      response(informBookingResponse, Notify {actionName = searchFlights})
    } else {
      // This is invalid because this response act is not a Notify response act
      response(confirmFlightBooking, ConfirmAction {actionName = bookFlight})
    }
    }
    
  • The type of the conditional expression is the same as the type of the first expression block. Therefore, the final expression in each of the conditional expression's block expressions must have the same type.

    // An invalid example
    // The types of the two block expressions do not match. The first block returns type SearchFlightsResult
    // and the second block returns type BookingDetail
    if (condition) {
    ...
    searchResult = searchFlights(bookFlightRequest.fromCity, bookFlightRequest.toCity,
                  bookFlightRequest.startDate)
    } else {
    ...
    bookingDetail = bookFlight(searchResult, flightDetail.ordinal)
    }