【问题标题】:What's a good way to write a F# Type Provider for Microsoft's Luis?为 Microsoft 的 Luis 编写 F# 类型提供程序的好方法是什么?
【发布时间】:2016-08-19 09:54:25
【问题描述】:

玩过微软的 Luis + bot 框架后,我的“这将是一个很好的类型提供者”的感觉开始刺痛。不幸的是,类型提供者不能输出有区别的联合。我希望做类似以下的事情,但这是不可能的:

type Luis = LuisProvider<@"LuisId",@"LuisPasskey">
let IntentMatcher Intent =
    match intent with
    | Luis.Intents.Greeting -> GreetingHandler()
    | Luis.Intents.SetAlarm title startDate startTime -> AlarmHandler title startDate startTime
    | _ -> CouldNotUnderstand()

Luis 意图和它们的参数都可以通过 APIs 获得,这使得它们成为 typeProviderization 的绝佳候选者

这里是一个来自示例 C# 机器人的处理程序作为参考(我认为它可能更干净,在 F# 中更安全):

public const string Entity_Alarm_Title = "builtin.alarm.title";
public const string Entity_Alarm_Start_Time = "builtin.alarm.start_time";
public const string Entity_Alarm_Start_Date = "builtin.alarm.start_date";
public const string DefaultAlarmWhat = "default";

[LuisIntent("builtin.intent.alarm.set_alarm")]
public async Task SetAlarm(IDialogContext context, LuisResult result)
{
        EntityRecommendation title;
        if (!result.TryFindEntity(Entity_Alarm_Title, out title))
        {
            title = new EntityRecommendation(type: Entity_Alarm_Title) { Entity = DefaultAlarmWhat };
        }
        EntityRecommendation date;
        if (!result.TryFindEntity(Entity_Alarm_Start_Date, out date))
        {
            date = new EntityRecommendation(type: Entity_Alarm_Start_Date) { Entity = string.Empty };
        }
        EntityRecommendation time;
        if (!result.TryFindEntity(Entity_Alarm_Start_Time, out time))
        {
            time = new EntityRecommendation(type: Entity_Alarm_Start_Time) { Entity = string.Empty };
        }
        var parser = new Chronic.Parser();
        var span = parser.Parse(date.Entity + " " + time.Entity);
        if (span != null)
        {
            var when = span.Start ?? span.End;
            var alarm = new Alarm() { What = title.Entity, When = when.Value };
            this.alarmByWhat[alarm.What] = alarm;
            string reply = $"alarm {alarm} created";
            await context.PostAsync(reply);
        }
        else
        {
            await context.PostAsync("could not find time for alarm");
        }
        context.Wait(MessageReceived);
}

无论如何,问题是:有没有更多经验构建类型提供程序的人对我如何构建一个实际上可行的可读 dsl 有什么好的想法?

【问题讨论】:

    标签: f# dsl type-providers azure-language-understanding


    【解决方案1】:

    我对机器人框架不是特别熟悉,但我可以评论区分联合 - 我们在 F# 数据中面临类似的问题。

    如果您有&lt;One name="string" /&gt;&lt;Two id="42" /&gt;,最好为One of stringTwo of int 提供区分联合。我们所做的是提供一个类型:

    type OneOrTwo =
      member One : option<string>
      member Two : option<int>
    

    您可以遵循相同的模式并公开如下所示的 API:

    type Luis = LuisProvider<"LuisId", "LuisPasskey">
    
    let intentMatcher (intent:Luis.Intents) =
      match intent.Greetings, intent.SetAlarm with
      | Some(), _ -> greetingHandler()
      | _, Some(title, startDate, startTime) -> alarmHandler title startDate startTime
      | _ -> couldNotUnderstand()
    
    Luis.Connect().OnIntent
    |> Observable.subscribe intentMatcher
    

    它不像有区别的联合那么优雅,但它在技术上应该是可行的。

    我想另一种选择是将单个操作的处理程序公开为单独的事件,然后您可以编写如下内容:

    type Luis = LuisProvider<"LuisId", "LuisPasskey">
    
    let luis = Luis.Connect()
    
    luis.BuiltIn.Greetings 
    |> Observable.add greetingHandler
    
    luis.BuiltIn.SetAlarm 
    |> Observable.add (fun (title, startDate, startTime) -> 
         alarmHandler title startDate startTime)
    

    现在我想起来,这可能会更好,但这取决于机器人框架的典型用途。

    【讨论】:

    • 托马斯你是明星!两者中的后者看起来很完美:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多