2016-12-09 2 views
8

Я пытался узнать несколько F #, посмотрев на последние годы AdventOfCode решения. Я наткнулся на это neat peice of code, который я не могу разобрать вообще:Отладка Seq.sumBy

i 1|>Seq.sumBy(" (".IndexOf) 

Примечания, я считаю, я понимаю предыдущую строку (в ссылке):

let i n=System.IO.File.ReadAllText(sprintf "%s/input/input%d.txt"__SOURCE_DIRECTORY__ n) 

Который создает функцию i, которая принимает integer n и читает файл inputN.txt и возвращает его как строку. Поэтому i 1 возвращает input1.txt как строку.

Тогда |> просто обжигающе строка (или массив символов?) В качестве первых паров к следующей функции, которая Seq.sumBy

Но тогда вещи начинают ломаться вниз ...

sumBy кажется прямым достаточно вперед:

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

Но IndexOf строки " (" меня озадачило.

Теперь я не хочу, чтобы здесь были рыбы, что я хотел бы знать. Как новичок на этом иностранном языке, когда я научился работать больше бит F #, как я могу взять этот кусок кода и разложить его на более мелкие части, чтобы проверить его, чтобы выяснить, что происходит? Это сводит меня с ума, что у меня есть решение, есть google/so, и я до сих пор не могу понять этот код.

Может ли кто-нибудь показать мне более мелкие фрагменты, чтобы я мог сам найти ответ?

+0

первоначально я принял ответ Рида, который помог мне безмерно. Но ответ Маркса поразил «помочь мне отлаживать» часть блестяще с его описательными примерами в FSI. Оба отличные. И какое замечательное сообщество F #, чтобы помочь мне. Приятно уйти от взаимодействия, желающего больше! Отличная работа для всех в этом сообществе. Спасибо! –

ответ

7

FSI - ваш друг. Я часто использую его, чтобы понять, как можно разбить функции. Если вы вставляете выражение FBL " (".IndexOf в FSI, на первый взгляд это выглядит не так:

> " (".IndexOf;; 

    " (".IndexOf;; 
    ^^^^^^^^^^^^ 

stdin(12,1): error FS0041: A unique overload for method 'IndexOf' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: System.String.IndexOf(value: char) : int, System.String.IndexOf(value: string) : int 

Как вы уже поняли, " (" является строкой, и IndexOf - метод на string. На самом деле, есть quite a few overloads этого метода, но только два с арностью 1.

Одним из таких перегрузок взять char в качестве входных данных, а другие принимают string в качестве входных данных.

Выражение " (".IndexOf если функция. Это короткая форма fun x -> " (".IndexOf x.

Вы также уже определили, что string реализует char seq, поэтому при использовании Seq модуль над ним, вы смотрите на каждый элемент последовательности. В этом случае каждый элемент имеет значение char, поэтому используемая здесь перегрузка должна быть той, которая принимает входной сигнал char.

Теперь, когда вы выяснили, какие перегружают в использовании, вы можете начать экспериментировать с ним в FSI:

> " (".IndexOf '(';; 
val it : int = 1 
> " (".IndexOf 'f';; 
val it : int = -1 
> " (".IndexOf 'o';; 
val it : int = -1 
> " (".IndexOf ' ';; 
val it : int = 0 

Очевидно, функция ищет индекс каждого входа char в " (", так каждый раз, когда вы проходите в '(', вы получаете 1 (потому что он индексируется с нулевой отметкой), а когда вход ' ', возвращаемое значение равно 0. Для всех других значений возвращаемое значение равно -1.

Входная строка, как "(foo bar)", также является char seq. Вместо того чтобы делать sumBy, вы можете попытаться трубы ее в Seq.map для того, чтобы понять, как каждый из элементов переводятся:

> "(foo bar)" |> Seq.map (" (".IndexOf) |> Seq.toList;; 
val it : int list = [1; -1; -1; -1; 0; -1; -1; -1; -1] 

Теперь Seq.map только переводит, но Seq.sumBy принимает все эти цифры и добавляет их вместе :

> "(foo bar)" |> Seq.sumBy (" (".IndexOf);; 
val it : int = -6 

Я до сих пор не могу догадаться, что цель, но тогда, я никогда не видел входную строку ...

+1

Марк, ваш ответ тоже блестящий. Спасибо. Этот рыхлый гусиный язык без парсетов или запятых просто убивает меня ! ;-) Но ваше объяснение помогло прояснить. Благодарим вас за подробный ответ (и ваши многочисленные вклады в преподавание в целом! –

8

Итак, мы можем разбить это на куски.

i 1|>Seq.sumBy(" (".IndexOf) 

Вы в отношении i 1. Это будет читать input1.txt и даст вам весь текст как string.

Итак, первый ключ заключается в том, что String implements IEnumerable<char> (char seq), что означает, что это то, что можно перечислить.

Далее, давайте посмотрим на части внутри из скобок:

" (".IndexOf 

Первая часть это просто строка: " (" и IndexOf является метод на строке. Он возвращает индекс, основанный на нулевом значении, или -1, если он не существует.

Как это метод, вы можете использовать его как функцию - так " (".IndexOf можно думать как:

(fun someChar -> 
       let str = " (" 
       str.IndexOf(someChar)) 

--------- Остановите здесь, если вы не хотите получить полный ответ подробно --------

 

 

 

 

 

 

 

 

 

 

В этом случае, если входной символ ' ', она возвращает 0, если это '(', он будет возвращать 1, а если что-нибудь еще, он будет возвращать -1.

Seq.sumBy берет каждый символ входной строки и передает ее в эту функцию, а затем суммирует результат. Это означает, что каждый вход '(' добавит 1, каждый вход ' ' добавит 0, и что-нибудь еще добавит -1 (который в этом случае будет ')' символов. Строка вроде этого "()" добавит 1, затем добавит -1, в результате чего 0, что соответствует goal of the day 1 advent challenge.

+2

Я думаю, что это '' («.IndexOf» в конечном итоге меня отбросило. Тот факт, что вы можете делать indexOf из «многих» символов. И ваша «забава» принесла свет! Все остальное сочетается. посмотрите на День 1, часть 2! Спасибо, Рид. (и спасибо за - Остановитесь здесь --- ;-) –