Проблема отступа в f # (vs2010 beta1) - PullRequest
4 голосов
/ 20 августа 2009

Я только учусь f #, поэтому возможно я делаю что-то очень глупое. Не стесняйтесь указывать мне на соответствующую документацию, я искал, но не смог найти. Я использую бета-версию Visual Studio 2010 на Windows 7 (.Net 4.0).

Все идет хорошо с моим первым проектом f #. Ну .. почти все. Особенно Я пишу очень простую функцию линейной интерполяции со следующим кодом:

let linterp (x:double) (xvalues:double list) (yvalues:double list) =
    let num_els = xvalues.Length
    if x <= xvalues.Head then 
        let result = yvalues.Head
    elif x >= (List.rev xvalues).Head then 
        let result = (List.rev yvalues).Head
    else for idx in [0 .. num_els] do 
        if List.nth xvalues idx >= x then 
            let x0 = xvalues.Item idx
            let y0 = yvalues.Item idx
            let x1 = xvalues.Item (idx+1)
            let y1 = yvalues.Item (idx+1)
            let result = y0 + (y1-y0)/(x1-x0)*(x - x0)
    result

и я получаю серию ошибок, которые полностью ускользают от моего понимания.

Это список ошибок и предупреждений:

  • "ошибка в выражении возврата для этого 'let'. Возможный правильный отступ" для первого, второго и последнего "let".

  • "возможно неправильный отступ: этот токен находится вне контекста, начатого в позиции (39:10). Попробуйте выполнить отступ этого маркера дальше или используйте стандартные правила форматирования" для "if"

  • «неполная структурированная конструкция в или перед этой точкой в ​​выражении» для последней строки (результата).

Я добавлю, что мне пришлось немного попотеть, чтобы аннотировать типы, поскольку по какой-то неизвестной мне причине компилятор мог правильно выводить для первого списка, но для второго тип всегда выводился как единица. Также, моя оригинальная версия не связывала имя результата, а просто «возвращала выражение», как в

if x <= xvalues.Head then 
    yvalues.Head

или

else for idx in [0 .. num_els] do 
    if List.nth xvalues idx >= x then 
        let x0 = xvalues.Item idx
        let y0 = yvalues.Item idx
        let x1 = xvalues.Item (idx+1)
        let y1 = yvalues.Item (idx+1)
        y0 + (y1-y0)/(x1-x0)*(x - x0)

Это оставляет ошибку под «for», говоря, что «Это выражение имеет тип единицы, но здесь используется с типом double» и что «if» возможно с неправильным отступом.

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

Заранее спасибо!

ps: я проверил, что вкладки правильно интерпретируются как пробелы в меню Сервис-> Параметры -> .... -> F # -> Вкладки

pps: это мой первый вопрос по SO: -)

Ответы [ 2 ]

5 голосов
/ 20 августа 2009
let linterp x (xvalues:double list) (yvalues:double list) =
    if x <= xvalues.Head then 
        yvalues.Head
    elif x >= (List.rev xvalues).Head then 
        (List.rev yvalues).Head
    else
        let idx = List.findIndex (fun e -> e >= x) xvalues
        let x0 = xvalues.Item idx
        let y0 = yvalues.Item idx
        let x1 = xvalues.Item (idx+1)
        let y1 = yvalues.Item (idx+1)
        y0 + (y1-y0)/(x1-x0)*(x - x0)
5 голосов
/ 20 августа 2009

Ваша проблема в том, что что-то вроде

let result = yvalues.Head

не является полным выражением, и поэтому не может образовывать тело одной из ветвей блока if. Ваш первоначальный подход был верным, за исключением того, что цикл for ... do не возвращает значащего значения (он возвращает (), который является единственным значением типа unit, как пытается объяснить компилятор; это похоже на void на таких языках, как C #). Вместо цикла for вы захотите использовать выражение со значением, которое вы ищете. Наименьшим изменением в вашем коде будет использование изменяемого значения, которое вы обязательно установите в цикле. Более идиоматический подход заключается в использовании встроенной функции, такой как List.fold, для сжатия списка в одно значение. Это осложняется тем фактом, что вам необходим доступ к последовательным записям в ваших списках (и что вам нужно одновременно работать с xvalues ​​и yvalues), что означает, что вам, вероятно, придется использовать List.zip и Seq.pairwise, уменьшить ясность для кого-то не привыкшего к F #.

Кроме того, есть несколько других изменений, которые вы можете применить, чтобы сделать ваш код более идиоматичным. Например, let x0 = xvalues.Item idx будет чаще записываться let x0 = xvalues.[idx]. Однако обратите внимание, что списки F # являются неизменяемыми, связанными списками и, следовательно, не поддерживают быстрый произвольный доступ. Это еще одна причина отдать предпочтение подходу, в котором используются встроенные операторы List.

...