Подтвердить что ты не робот

F # Вопросы качества жизни

Я начал кодирование в F # около 2 месяцев назад.

Мне очень нравится этот язык программирования. Я исхожу из фона С#, и каждый раз, когда мне нужно вернуться на С#, он кажется таким громоздким и раздутым.

Но есть еще вещи, которые, по моему мнению, проблематичны в F #, и это то, к чему относятся мои вопросы:

  • Нет автоматического завершения, как VS имеет для С# правильно? Например. внутри функции, которая принимает параметр aParameter, если я пишу aPara, то автозаполнение не появляется. Есть ли функциональность внутри ВС, которая может решить эту проблему и о которой я не знаю?

  • Отладка утомительна, если не сказать больше. Поскольку F # поддерживает компоновку/цепочку или то, что вы хотите назвать, я обычно стараюсь объединить как можно больше вещей (везде, где это имеет смысл). Пример:

    correctedData 
    |> List.filter (fun (_, r, _) -> r <= 3) 
    |> Seq.ofList 
    |> Seq.groupBy (fun (_, r, cti) -> (r,cti))                            
    |> Seq.map (fun ((r,cti),xs) -> (r, cti, Seq.length xs)) 
    |> Seq.toList
    

И это всего лишь четверть всей моей цепочки. Всякий раз, когда я что-то ввязываю в эти цепи, мне очень сложно отлаживать, где все пошло не так.

Я делаю эту цепочку неправильно (злоупотребляя ею)? С моей точки зрения, ничто промежуточное от этой цепочки имеет смысл существовать атомарно, поэтому нет причин иметь промежуточные ценности. Но из-за этой семантической точки зрения я также теряю способность иметь промежуточные ценности, которые помогают мне отлаживать. Поэтому мне нужно вставить их в код, отладить, а затем удалить их снова. Но это потраченное впустую усилие. Есть ли способ обойти это?

Кроме того, отладка анонимной функции List.map внутри цепочки кажется неудобной и сложной по сравнению с, например, цикл for.

Я уверен, что у меня что-то не хватает, и что мой текущий способ отладки, вероятно, не оптимален - не длинным выстрелом - поэтому любые предложения приветствуются.

4b9b3361

Ответ 1

1. Нет автоматического завершения, как у VS для С# справа

Для F # автозаполнение. Он не запускается автоматически, когда вы начинаете вводить текст. Если вы находитесь в Visual Studio и введите aPara, а затем нажмите Ctrl + Space, он должен быть автозаполнен до aParameter, если он находится в области. Аналогично, вы можете сделать это в области верхнего уровня, чтобы увидеть доступные типы и пространства имен. Автозаполнение также запускается автоматически при вводе .

2. Отказывание утомительно, чтобы сказать наименьшее

Я бы согласился с этим - отладочные конвейеры (особенно с ленивыми последовательностями) сложны. Это немного запутанно, даже когда вы на С#, но С# делает удивительно хорошую работу на этом. Есть два способа справиться с этим:

  • Используйте F # Interactive больше. Сначала я пишу большую часть своего кода в файле F # Script, где вы можете запускать свои частично полные решения и сразу видеть результаты. Для меня это в значительной степени заменяет отладку, потому что к моменту завершения моего кода я знаю, что он работает.

  • Вы можете определить функцию tap, которая материализует данные в конвейере и позволяет вам видеть, что происходит через трубу. Я не использую это очень много, но я знаю, что некоторым нравится:

    let tap data = 
      let materialized = List.ofSeq data
      materialized
    

    Затем вы можете использовать его в своем конвейере:

    correctedData 
    |> List.filter (fun (_, r, _) -> r <= 3) 
    |> tap
    |> Seq.groupBy (fun (_, r, cti) -> (r,cti))                            
    |> tap
    |> Seq.map (fun ((r,cti),xs) -> (r, cti, Seq.length xs)) 
    |> Seq.toList
    

    Это добавляет некоторый шум в конвейер, но вы можете удалить его снова, как только закончите с отладкой.

Ответ 2

Вопрос об улучшении опыта отладки с F # имеет много аспектов, поэтому он заслуживает большой статьи. Поэтому я боюсь, что вопрос будет закрыт. Тем не менее, вот два аккуратных трюка, которые я использую. Я должен отметить, что я также большой поклонник трубопроводного подхода, и поэтому сталкиваюсь с теми же проблемами.

Знайте свои типы.

Наличие значения, пронизывающего цепочку из многих преобразований, может быстро привести к затруднению запоминания точных типов на каждом шаге. Трюк:

value
|> transformation1
|> fun x -> x
|> transformation2

Это позволяет вам:

  • см. точный тип x во время разработки;
  • установить точку останова (поместить курсор в тело функции) и увидеть значение во время отладки;
  • Даже если забыли в коде после завершения, это оставляет минимальный след.

Условно вывести значения в консоль.

Сложные лямбды, точки останова могут мало помочь. Вот еще один трюк, связанный с тем, который описан в ответе @Tomas: напишите небольшую функцию, например:

let inline debug x =
#if DEBUG
    if System.Console.CapsLock then
        printfn "%A" x
        // obviously, it must not be necessarily printf;
        // it can be System.Diagnostics.Debug.WriteLine()
        // or any other logger tool that exists in the project.
#endif
    x

Код использования выглядит следующим образом:

value
|> transformation1
|> fun x -> x
|> debug
|> transformation2

Идея такова:

  • вы устанавливаете точку останова непосредственно перед вызовом debug, как описано выше;
  • переключатель Caps Lock on
  • и Step Over или просто запустить приложение

Если у вас несколько мест, где debug вызов сидит, они не испортят вывод.

Ответ 3

В отладке | > проблема трубопроводов - попробуйте иметь персональный стандарт кодирования, в котором у вас не более трех или не более четырех строк в таком конвейере. Когда они получат больше времени, рефакторинг. Это то, что я делаю, и это очень помогает.