2016-10-29 6 views
2

Im пытается сделать функцию, которая примет строку и целое число как аргументы/ввод.F # Два разных типа аргументов функции

let rec twoTwo (s : string) (n : int) = 
    match n with 
    |0 -> 0 
    |_ -> s + (twoTwo s (n-1)) 

printfn "%A" (twoTwo "string" 5) 

Здесь я получаю сообщение об ошибке, что тип int не соответствует строке типа. Это за пределами меня почему? Рекурсивный вызов заключается в том, что это ошибка типа missmatch.

Что не так?

+1

Возможно, лучше сделать 'n'' uint', а не 'int', потому что если отрицательное число передано в него, произойдет сбой. – stt106

+0

@ stt106 Почему в этом случае помощь без знака? Обычный способ справиться с этим заключается в том, чтобы добавить символ 'when' к совпадению шаблонов на счетчике' n' и использовать 'failwith' из оператора catch-all' _ -> с ошибкой «Woot?» '. В конце концов, какие гарантии у вас есть, что отрицательное число передано? Может быть, некоторые Unicode или байты будут переданы. – s952163

+1

@ s952163, если n является единицей типа, тогда компилятор даже не позволит вам передавать байты или Unicode. – stt106

ответ

7

Вот вопрос, о котором нужно подумать: что возвращает ваша функция?

Если вы посмотрите на первой ветви match, вы возвращаете int, но во втором отделении вы используете свой собственный возвращаемое значение в конкатенации с string, так что возвращаемое значение должно быть строкой.

Итак, что это? Компилятор не может сказать, что вы имели в виду, поэтому он жалуется.

В ответ на ваш комментарий:
Составитель первого чтения нуля в первой ветви, и на этом основании решили, что возвращение функции должен быть int. После этого компилятор столкнулся с конкатенацией строк, увидел, что уже выбранный тип возвращаемого значения не подходит, и выдает сообщение об ошибке.
Если ветви были отменены, то логика также будет отменена: компилятор сначала столкнется с конкатенацией, и на этой основе решит, что тип возврата должен быть string. После этого он столкнется с нулем, увидит, что он не соответствует ранее заданному типу возврата и жалуется. В этом случае ошибка была бы равна нулю.
Вы бы пожаловались в этом случае? Зачем? Как вы ожидаете, что компилятор узнает, что ошибка находится на нуле, а не на конкатенации? Весь компилятор может знать, что две ветви не совпадают. Он не знает, какой из них правильный.

Вы,, считаете, что это очевидно, потому что вы знаете, что вы хотели сделать. Но компилятор не знает, что вы собираетесь делать, он может видеть только то, что вы написали.

На другом языке, который вы могли бы назвать более "rookie-friendly", например, C# (или Java), эта ситуация не возникает, поскольку вы всегда вынуждены явно указывать все возврат и типы параметров. Это делает ошибки более понятными, потому что теперь компилятор может сказать, какая ветка неверна: это та, которая не согласуется с явно объявленным типом возврата.
Но если вы думаете об этом, вы просто переместили проблему вверх: как компилятор знает, что явно объявленный тип верен? Компилятор просто принимает, что объявленный тип является конечной истиной, но это просто соглашение. Да, это очень хорошо знакомо, но так же произвольно, как чтение программы в порядке.

Однако, если вы найдете этот подход более удобным для вас, вы можете полностью использовать его в F #. F # позволяет (хотя не требует) спецификаций явных типа во всех местах, где С # (и затем некоторыми):

let rec twoTwo (s : string) (n : int) : string = 
    match n with 
    |0 -> 0 // Error on this line: this expression was expected to have type string, but here has type int 
    |_ -> s + (twoTwo s (n-1)) 

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

+0

Да, теперь, когда ты говоришь мне, я могу это увидеть. Хотя почему это делает ошибку во второй ветви, когда это первая ветвь, которая является проблемой ... F # действительно не новичок. – Nulle

+1

@Nulle, потому что компилятор «читает» сначала «int» как return, а затем «string», поэтому последние не соответствуют первому. Если вы инвертируете две ветви (отложив в сторону, что первая - это все совпадение), ошибка все равно возникнет во второй ветви (с обратным сообщением о типах) – Sehnsucht

+1

@Nulle, я обновил ответ в ответ на ваш комментарий. –

Смежные вопросы