Это не точный ответ, как я не уверен, что вы имеете в виду, но это должно дать вам некоторые идеи.
let add01 (numbers:string) =
let delimiters : char array = [|',';'\n'|]
let inputArray : string array = numbers.Split(delimiters)
let numbers : string list = Array.toList(inputArray)
let rec add (numbers : string list) (total : int) : int =
match (numbers : string list) with
| ""::t ->
add t total
| h::t ->
let number = System.Int32.Parse h
let total = total + number
add t total
| [] -> total
add numbers 0
let numbers = "1,2,3\n4,5,6\n\n"
let result = add01 numbers
Приведенный ниже код вызывает ошибку, почему?
// Type mismatch. Expecting a
// int -> 'a
// but given a
// string -> int
// The type 'int' does not match the type 'string'
let result = numbers |> add ","
|> add "\n"
Поскольку это ошибка о том, что два типа не согласны нужно понимать type inferencing и как решать такие проблемы. Я не буду объяснять здесь вывод типа, поскольку это большая тема сама по себе, однако я приведу пример шаблона, который успешно работает с большинством времени для меня при разрешении таких ошибок.
Когда F # компилирует код, он использует вывод типа, чтобы добавить недостающие типы к функциям и значениям перед выполнением проверки типа, и это проверка типа, которая терпит неудачу. Таким образом, чтобы увидеть, что видит компилятор для типов, мы вручную добавим их здесь и отделим части кода, которые не вызывают проблемы, оставляя нас с причиной ошибки, надеюсь, что-то в этом случае становится очевидным для исправления.
Единственные вещи, которые имеют следующие типы:
- результат
- =
- номера
- |>
- добавить
- ""
- "\ п"
типов для значений легко:
- результата: INT
- номера: строка
- "": строка
- "\ п": строка
Я надеваю Напомню, что F # обрабатывает equals (=) как функцию, но вот как это можно понять.
=: 'а ->' оператор А
трубопровода
let (|>) (x : 'a) f = f (x : 'a)
Для решения проблемы просто думаю оператора трубопровода, как syntactic sugar.
См. Примеры ниже для лучшего понимания.
Надстройка функция
добавить: строка -> строка -> Int
Так позволяет уточнить ошибку вплоть до своей сути.
//Type mismatch. Expecting a
// int -> 'a
//but given a
// string -> int
//The type 'int' does not match the type 'string'
let result = numbers |> add ","
|> add "\n"
Добавьте сигнатуры типа к значениям и убедитесь, что мы получим ту же ошибку. Это то, что сделал бы метод вывода, и мы сделали это вручную.
//Type mismatch. Expecting a
// int -> int
//but given a
// string -> int
//The type 'int' does not match the type 'string'
let (result : int) = (numbers : string) |> add ("," : string)
|> add ("\n" : string)
Теперь подумайте о коде как математическом выражении, которое может быть учтено.
Фактор первого оператора трубопровода и убедитесь, что мы получаем ту же ошибку. Уведомление об ошибке в настоящее время только часть r2
//Expecting a
// int -> 'a
//but given a
// string -> int
//The type 'int' does not match the type 'string'
let (result : int) =
let r1 = (numbers : string) |> add ("," : string)
let r2 = r1 |> add ("\n" : string)
r2
Отменить синтаксический сахар для второго оператора трубопровода и проверки мы получаем ту же ошибку. Обратите внимание, что ошибка теперь является только частью r2; в частности аргумент r1
//This expression was expected to have type
// string
//but here has type
// int
let (result : int) =
let r1 = (numbers : string) |> add ("," : string)
let r2 = add ("\n" : string) r1
r2
Добавить тип в r1 и убедиться, что мы получим ту же ошибку.
//This expression was expected to have type
// string
//but here has type
// int
let (result : int) =
let (r1 : int) = (numbers : string) |> add ("," : string)
let r2 = add ("\n" : string) r1
r2
На этом этапе ошибка должна быть очевидной. Результатом первого оператора конвейера является int
и передается функции добавления в качестве второго аргумента. Функция добавления ожидает string
для второго аргумента, но ему присваивается int
.
Чтобы лучше понять, как работает оператор трубопровода, я создал эквивалентный пользовательский оператор для этой демонстрации.
Это вспомогательные функции для демонстрации.
let output1 w =
printfn "1: %A" w
let output2 w x =
printfn "1: %A 2: %A" w x
let output3 w x y =
printfn "1: %A 2: %A 3: %A" w x y
let output4 w x y z =
printfn "1: %A 2: %A 3: %A 4: %A" w x y z
Использование выходных функций без оператора трубопровода.
output1 "a"
1: "a"
output2 "a" "b"
1: "a" 2: "b"
output3 "a" "b" "c"
1: "a" 2: "b" 3: "c"
output4 "a" "b" "c" "d"
1: "a" 2: "b" 3: "c" 4: "d"
Обратите внимание, что выход находится в том же порядке, что и вход.
Использование выходных функций с оператором трубопровода.
// пусть (|>) = XF FX
"a" |> output1
1: "a"
"a" |> output2 "b"
1: "b" 2: "a"
"a" |> output3 "b" "c"
1: "b" 2: "c" 3: "a"
"a" |> output4 "b" "c" "d"
1: "b" 2: "c" 3: "d" 4: "a"
ВНИМАНИЕ, что последний аргумент для выходных функций значение слева от оператора трубопровода («а») из-за использования оператора трубопровода (|>).
// См. Раздел 3.7 раздела F# specification о том, как определить определяемые пользователем операторы.
Использование выходных функций с помощью определенного оператора конвейера.
let (@.) x f = f x
"a" @. output1
1: "a"
"a" @. output2 "b"
1: "b" 2: "a"
"a" @. output3 "b" "c"
1: "b" 2: "c" 3: "a"
"a" @. output4 "b" "c" "d"
1: "b" 2: "c" 3: "d" 4: "a"
Требуется ли, чтобы каждый разделитель выполнялся отдельным вызовом функции добавления? Вы пытаетесь узнать о составе функции или просто просто суммировать строку? Если вы пытаетесь суммировать строку, я предлагаю вам сделать один вызов, передающий все разделители как массив в [Split] (https://msdn.microsoft.com/en-us/library/b873y76a (v = vs .110) .aspx). –
Мы должны задать вопрос: «Тип« int »не соответствует типу« строка »отдельного вопроса. Если бы вы могли спросить об этом, я мог бы переместить эту часть ответа на него. Это действительно два вопроса, и другая часть должна быть легче найти. –