【问题标题】:F# FSI does not hit break inside inline functionF# FSI 在内联函数内没有中断
【发布时间】:2018-12-23 11:34:45
【问题描述】:

我有几个通用的内联函数,例如:

let inline getRatesImpl<'T when 'T : (member enantiomer : 'T) and 'T : equality> 
    (d : Dictionary<'T, (ReactionRate option * ReactionRate option)>) 
    (calculateRates : 'T -> RelatedReactions<'T>)
    (r : 'T) = 

    match d.TryGetValue r with 
    | true, rates -> 
        rates
    | false, _ -> 
        updateRelatedReactions d (calculateRates r) r

函数是这样使用的:

type FoodCreationModel (p : FoodCreationParam) = 
    let rateDictionary = new Dictionary<FoodCreationReaction, (ReactionRate option * ReactionRate option)>()
    let calculateRates _ = getRates (Some p.foodCreationRate, Some 1.0) (None, None)

    member __.getRates r = 
        getRatesImpl rateDictionary calculateRates r

    member __.inputParams = p

当我在getRatesImpl 中插入一个break 时,它不会在FSI 中被击中。即使我在getRates(在线getRatesImpl rateDictionary calculateRates r)上休息一下,然后按F11,FSI 也不会进入inline getRatesImpl。但是,它确实有效,我可以通过查看字典在调用前后的变化来检查它。

其中一些内联函数非常复杂,我真的需要不时调试它们。

问题是怎么做的?

【问题讨论】:

  • 我发现调试中断不适用于内联。你能将内联函数分成两部分吗?需要内联的部分和非内联的部分。内联函数提取所有只能在内联函数中收集的信息,并调用包含复杂逻辑的非内联部分。这样您就可以调试非内联逻辑。除了我认为你需要依赖printfn
  • @ Justanothermetaprogrammer 虽然很不幸,但 FSI 无法在内联函数中进行调试可以作为答案。我很乐意将其标记为答案,您将其作为答案而不是评论:)

标签: debugging f# inline f#-interactive


【解决方案1】:

您的代码可能可以更改以避免需要复杂的inlines。

避免使用 SRTP 的一种方法是将所需函数作为参数而不是约束传递:

let getRatesImpl
        (d : Dictionary<'T, (ReactionRate option * ReactionRate option)>) 
        (getEnantiomer: 'T -> 'T)
        (calculateRates : 'T -> RelatedReactions<'T>)
        (r : 'T) = 

    match d.TryGetValue r with 
    | true, rates -> 
        rates
    | false, _ -> 
        updateRelatedReactions d getEnantiomer (calculateRates r) r

现在getRatesImpl 不需要内联了。

如果需要多个函数,则可以传递函数记录。

【讨论】:

  • 感谢 cmets。 1.整个系统建立在DU/记录树上。提议的IEnantiomer 接口是一种C# 做事方式。是的,它有效,但成本太高:首先,将使用类而不是 DU / 记录 => 所有比较都必须手动重载,然后才能在各种字典中轻松使用对象。 2. 问题不在于更好地实现字典,而在于如何调试 F# 内联函数,我选择了最简单的函数来说明问题。如果您有这个问题的答案,我将不胜感激。
  • 2.- 我包含了 memoization 库,因为您似乎以一种相当复杂的方式执行此操作,这迫使您使用 SRTP,而这反过来又迫使您使用内联。当然,调试问题的答案是您不能调试内联,因为它们不是一个函数,而是多个函数,每个调用一个函数。如果您想添加断点,请远离 SRTP 和内联函数。
  • 1.- 我提出接口是因为您的示例使用的是类,正如您所说的“是 C# 的东西”。顺便说一句,使用接口不会强迫您将 DU 或记录更改为类。他们,DU 和记录,可以完美地实现接口。我更改了答案以显示这一点。
  • 话虽如此,我不再推荐使用接口,因为您不想使用OOP,我对此表示赞赏。您可能不需要 SRTP,但一个简单的 getEnantiomer 函数就可以了。只需发布您的对映异构体函数,也许我们可以弄清楚如何重组它们,这样您就可以轻松调试它们而无需内联。
  • 感谢 cmets。我还没有发现在纯 F# 代码中使用接口的需要。 SRTP 可以做到这一点,而且不会臃肿。我已经有函数let inline getEnantiomer i = ((^T) : (member enantiomer : 'T) (i)),它被一些通用函数使用,最终被getRatesImpl 使用,这迫使它具有通用约束member enantiomer。问题是无法调试内联函数:(这似乎是当前实现的一个缺点。
猜你喜欢
  • 2020-02-26
  • 1970-01-01
  • 2015-03-08
  • 2011-07-13
  • 1970-01-01
  • 2015-02-09
  • 2016-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多