@Fsharp_chat

Страница 19 из 772
Roman
29.03.2017
17:38:12
Хотя как я сейчас понимаю эти два подхода не плохо комбинируются

ща

Более общим выглядит все же варирант request responce момент, анпишу где-нидь

Arseniy
29.03.2017
17:39:27
они не эквивалентны в том, что в его концепции одно событие может иметь несколько обработчиков, и каждый сам решает, хендлить или нет. а тут придётся дублировать код в ветках матча

Google
Igor
29.03.2017
17:39:29
Хотя как я сейчас понимаю эти два подхода не плохо комбинируются
А как ты предагаешь сделать string -> TGUCommand option?

Roman
29.03.2017
17:40:05
А как ты предагаешь сделать string -> TGUCommand option?
Но это не крутой подход, подход req-responce гориздо лушче все же.

Igor
29.03.2017
17:40:52
let parse str = ... string -> TGCommand
ты мне реализацию покаж ?

Roman
29.03.2017
17:42:07
ты мне реализацию покаж ?
если там одни команды, то можно и вручнюу пропарсить типа

Супернавино match strList with | ["/start"] -> Start |["/say"; word ] -> Say word | ["/add"; x; y] -> (int.parse x, int parse y) |> Add

если становится сложнее, то подключаем какой-нибудь Fparsec

type Schdule = | StartCron of CronExpression | GetNextTimeCron | StopCron | InfoCron type TGCommand = | Start | Showstat | Cron of Schdule let resultSatisfies predicate msg (p : Parser<_, _>) : Parser<_, _> = let error = messageError msg fun stream -> let state = stream.State let reply = p stream if reply.Status <> Ok || predicate reply.Result then reply else stream.BacktrackTo(state) // backtrack to beginning Reply(Error, error) let str s : Parser<string, unit> = pstring s let pToString p = p |>> fun x -> x.ToString() let prange p = pipe3 p (pchar '-') p (fun a _ c -> sprintf "%s-%s" a c) let plist (p : Parser<'a, _>) = sepBy1 p (pchar ',') |>> fun x -> System.String.Join(",", x) let plapse (p1 : Parser<'a, _>) (p2 : Parser<'b, _>) = pipe3 p1 (pchar '/') p2 (fun a _ c -> sprintf "%s/%s" a c) let pstar : Parser<string, unit> = pstring "*" let pquestionMark : Parser<string, unit> = pstring "?" let pintMinMax min max = pint32 |> resultSatisfies (fun x -> x <= max && x >= min) (sprintf "This value must be %d-%d" min max) let [ pfiftyNineS; ptwentyThreeS; pthirtyOneS; pelevenS; psevenS ] : list<Parser<string, unit>> = [ pToString (pintMinMax 0 59) pToString (pintMinMax 0 23) pToString (pintMinMax 1 31) pToString (pintMinMax 0 11) pToString (pintMinMax 1 7) ] let pcronPart (p : Parser<string, unit>) = choice [ attempt (plapse pstar p) attempt (plapse p p) attempt (prange p) (plist p) pstar p ] let [ pSecOrMin; pHours; pDaysOfMonth; pMonth; pDayOfWeek ] = [ pcronPart pfiftyNineS pcronPart ptwentyThreeS (pquestionMark <|> pcronPart pthirtyOneS) pcronPart pelevenS (pquestionMark <|> pcronPart psevenS)] let pipe6sep p1 p2 p3 p4 p5 p6 func = p1 >>= fun a -> (unicodeSpaces1 >>. p2) >>= fun b -> (unicodeSpaces1 >>. p3) >>= fun c -> (unicodeSpaces1 >>. p4) >>= fun d -> (unicodeSpaces1 >>. p5) >>= fun e -> (unicodeSpaces1 >>. p6) >>= fun f -> preturn (func a b c d e f) let pcron : Parser<string, unit> = pipe6sep pSecOrMin pSecOrMin pHours pDaysOfMonth pMonth pDayOfWeek (fun sec min h dom m dow -> System.String.Join(" ", [ sec; min; h; dom; m; dow ])) let pstartCmd botname = str ("/start" + botname) <|> str "/start" >>% Start let pshowstatCmd botname = str ("/showstat" + botname) <|> str "/showstat" >>% Showstat let pcronGetTime = str "get time" >>% GetNextTimeCron let pcronStop = str "stop" >>% StopCron let pcronInfo = str "info" >>% InfoCron let pcronExpression = pcron >>= (fun x -> try (x |> CronExpression) |> Schdule.StartCron |> preturn with :? System.FormatException as fe -> fail (fe.Message)) let pcronCmd botname = (str ("/cron" + botname) <|> str "/cron") >>. unicodeSpaces1 >>. (pcronExpression <|> pcronGetTime <|> pcronStop <|> pcronInfo ) |>> fun x -> Cron(x) let pcommand (botname : string) = unicodeSpaces >>. ((pstartCmd botname) <|> (pcronCmd botname) <|> (pshowstatCmd botname))

type Schdule = | StartCron of CronExpression | GetNextTimeCron | StopCron | InfoCron type TGCommand = | Start | Showstat | Cron of Schdule let resultSatisfies predicate msg (p : Parser<_, _>) : Parser<_, _> = let error = messageError msg fun stream -> let state = stream.State let reply = p stream if reply.Status <> Ok || predicate reply.Result then reply else stream.BacktrackTo(state) // backtrack to beginning Reply(Error, error) let str s : Parser<string, unit> = pstring s let pToString p = p |>> fun x -> x.ToString() let prange p = pipe3 p (pchar '-') p (fun a _ c -> sprintf "%s-%s" a c) let plist (p : Parser<'a, _>) = sepBy1 p (pchar ',') |>> fun x -> System.String.Join(",", x) let plapse (p1 : Parser<'a, _>) (p2 : Parser<'b, _>) = pipe3 p1 (pchar '/') p2 (fun a _ c -> sprintf "%s/%s" a c) let pstar : Parser<string, unit> = pstring "*" let pquestionMark : Parser<string, unit> = pstring "?" let pintMinMax min max = pint32 |> resultSatisfies (fun x -> x <= max && x >= min) (sprintf "This value must be %d-%d" min max) let [ pfiftyNineS; ptwentyThreeS; pthirtyOneS; pelevenS; psevenS ] : list<Parser<string, unit>> = [ pToString (pintMinMax 0 59) pToString (pintMinMax 0 23) pToString (pintMinMax 1 31) pToString (pintMinMax 0 11) pToString (pintMinMax 1 7) ] let pcronPart (p : Parser<string, unit>) = choice [ attempt (plapse pstar p) attempt (plapse p p) attempt (prange p) (plist p) pstar p ] let [ pSecOrMin; pHours; pDaysOfMonth; pMonth; pDayOfWeek ] = [ pcronPart pfiftyNineS pcronPart ptwentyThreeS (pquestionMark <|> pcronPart pthirtyOneS) pcronPart pelevenS (pquestionMark <|> pcronPart psevenS)] let pipe6sep p1 p2 p3 p4 p5 p6 func = p1 >>= fun a -> (unicodeSpaces1 >>. p2) >>= fun b -> (unicodeSpaces1 >>. p3) >>= fun c -> (unicodeSpaces1 >>. p4) >>= fun d -> (unicodeSpaces1 >>. p5) >>= fun e -> (unicodeSpaces1 >>. p6) >>= fun f -> preturn (func a b c d e f) let pcron : Parser<string, unit> = pipe6sep pSecOrMin pSecOrMin pHours pDaysOfMonth pMonth pDayOfWeek (fun sec min h dom m dow -> System.String.Join(" ", [ sec; min; h; dom; m; dow ])) let pstartCmd botname = str ("/start" + botname) <|> str "/start" >>% Start let pshowstatCmd botname = str ("/showstat" + botname) <|> str "/showstat" >>% Showstat let pcronGetTime = str "get time" >>% GetNextTimeCron let pcronStop = str "stop" >>% StopCron let pcronInfo = str "info" >>% InfoCron let pcronExpression = pcron >>= (fun x -> try (x |> CronExpression) |> Schdule.StartCron |> preturn with :? System.FormatException as fe -> fail (fe.Message)) let pcronCmd botname = (str ("/cron" + botname) <|> str "/cron") >>. unicodeSpaces1 >>. (pcronExpression <|> pcronGetTime <|> pcronStop <|> pcronInfo ) |>> fun x -> Cron(x) let pcommand (botname : string) = unicodeSpaces >>. ((pstartCmd botname) <|> (pcronCmd botname) <|> (pshowstatCmd botname))
коленочный не аккуратный код

большая часть для того чтоб парсить крон, это от нечего делать.

Igor
29.03.2017
17:48:29
коленочный не аккуратный код
Закинь на gist или pastebin, потом поизучаю

Roman
29.03.2017
17:48:40
https://gist.github.com/Neftedollar/6ea29f7ff8b848a799d3445778a76471'

Google
Igor
29.03.2017
17:53:03
https://gist.github.com/Neftedollar/6ea29f7ff8b848a799d3445778a76471'
ОК, но с подсветкой кода было бы лучше

Roman
29.03.2017
17:53:39
ОК, но с подсветкой кода было бы лучше
мой первй гист, как включить подсветку?

Igor
29.03.2017
17:54:24
мой первй гист, как включить подсветку?
наверно надо было дать файлу имя с расширение .fs

Arseniy
29.03.2017
17:54:24
расширения файла укажи, типо yoba.fs

Roman
29.03.2017
17:55:03
спасибо, я думал он поймет по fs что там fs ) надо было fs.fs написать

Roman
29.03.2017
17:57:30
pstring это из Fparsec?
Да. http://www.quanttec.com/fparsec/reference/charparsers.html#members.pstring

Igor
29.03.2017
17:57:57
Да. http://www.quanttec.com/fparsec/reference/charparsers.html#members.pstring
а на какой строке закачивается код парсинга?

Roman
29.03.2017
17:59:06
а на какой строке закачивается код парсинга?
pstring "/start" вернет тебе Parser<string,_> если я правильно понял вопрос

Igor
29.03.2017
18:02:11
поясни?
Не важно. А где у тебя в коде используется TGCommand Самое смешное что я сначала тоже сделал: type Action = List | Help | Add of string | Remove of string и переводил строку с начало в Action, потом уже его паттернматчил. Но во время очердного рефакторинг мне показалось это лишним действием и я дропнул его. И теперь PM прям строку

Roman
29.03.2017
18:03:45
Не важно. А где у тебя в коде используется TGCommand Самое смешное что я сначала тоже сделал: type Action = List | Help | Add of string | Remove of string и переводил строку с начало в Action, потом уже его паттернматчил. Но во время очердного рефакторинг мне показалось это лишним действием и я дропнул его. И теперь PM прям строку
let msg = run (Parser.pcommand botname) message.Text match msg with | Success(result, _, _) -> match result with | Parser.Start -> replyTo "Привет! Я бот блалалалал! Отправь мне /showstats /cron 'тут параметры cron'" | Parser.Showstat -> CronJob.job api message.Chat.Id message.MessageId | Parser.Cron cron -> cronHandler api message replyTo cron | Failure(errMsg, a, b) -> replyTo ("`" + errMsg + "`")

Roman
29.03.2017
18:04:52
все. Дальше уже type Schdule = | StartCron of CronExpression | GetNextTimeCron | StopCron | InfoCron используется

Nikolay
29.03.2017
18:05:14
Спасибо за помощь, буду раскуривать

Roman
29.03.2017
18:05:25
Спасибо за помощь, буду раскуривать
Посмотри все же как сделано в suave.io

Arseniy
29.03.2017
18:06:13
@Dolfik или почитай книжку что я сбросил, там основы на пальцах объясняются

Roman
29.03.2017
18:06:46
Спасибо за помощь, буду раскуривать
https://suave.io/routing.html вот тут пример того как потом можно было бы этот запрос от тг обрабатывать

Google
Nikolay
29.03.2017
18:08:42
@Dolfik или почитай книжку что я сбросил, там основы на пальцах объясняются
Книги по программированию не очень заходят, больше предпочитаю разбираться на решении практической задачи, хотя это конечно спорный подход, но пока он работает

Roman
29.03.2017
18:14:10
кстати как бонус в FParsec яполучил сообщение об ошибке парсинга ) оч удобно)

оно там довольно умное

А в чем прикол использовать команды, начинающиеся с / ?
все команды начинаются же на / если ты боту еще ничего не писал.

Nikolay
29.03.2017
18:18:17
А ещё такой вопрос, F# на .Net Core использует кто? У меня в 2015/2017 проект так и не получилось открыть, я так понял они поддержку ещё не допилили

Igor
29.03.2017
18:23:07
все команды начинаются же на / если ты боту еще ничего не писал.
Я просто у того же botfather вижу подсказки, я думал может это как-то связано.

Roman
29.03.2017
18:38:09
Я просто у того же botfather вижу подсказки, я думал может это как-то связано.
ну да. набери тут в пустом поле / и увидишь список комманд комбота. В ботфаезере можно эти команды указать и тогда будет "автокомплит", команды ботфазер принимает только с лидирующим /

кстати, F# для телеграм-ботов еще не плох тем, что можно на каждый чат создавать например по актору(да в C# тоже можно но только с помощью тяжеловесной akka.net) и там например хранить состояние чата, например если писать бота для игры в крестики нолики.

Привет, всем новоприбывшим. В файлах чата можно найти полезные книги.

Arseniy
29.03.2017
19:11:05
https://twitter.com/kot_2010/status/847163223660990464

Roman
29.03.2017
19:15:38
Я так понимаю оно сбросится при рестарте, поэтому не очень хорошо
при рестарте процесса, да. Но так и задать initial state можно.

если же рассматривать вариант акторы для чатботов в целом, то мне кажется это очень удобно. А если использовать akka.net или Orleans/Orleankka то там и слой персистентности сразу добавлен в реализацию акторов.

Nikolay
29.03.2017
19:18:50
Как в F# красиво сделать что-то типа такого list.Max(f => f.Id)?

Roman
29.03.2017
19:19:57
Igor
29.03.2017
19:26:17
list |> List.maxOf (fun x -> x.Id) как-то так
Надо кстати придумать более коротки синтаксис, когда что-то происходит с полем объекта, а то это часты кейс, а выходит длиннее чем в C# типа: list |> List.maxOf _.id |> ... Сейчас можно делать module l = List, что бы писать list |> l.maxOf (fun x -> x.Id)

Nikolay
29.03.2017
19:30:21
У меня так получилось для IEnumerable

Google
Nikolay
29.03.2017
19:30:22
updates |> Seq.map (fun x -> x.Id ) |> Seq.max

list.Select(f => f.Id).Max() для C#

Roman
29.03.2017
19:31:58
list.Select(f => f.Id).Max() для C#
на самом деле maxOf используется очень редко. А для краткости например чтоб избежать fun x -> x уже сделали ф-цию id

Evgeniy
29.03.2017
19:34:32
@angmarr https://github.com/fsharp/fslang-suggestions/issues/506

Есть такое предложение.

Nikolay
29.03.2017
19:35:02
Roman
29.03.2017
19:35:23
А это не костыльно?
по мне так не нужно, но если хочется, почему нет?

Igor
29.03.2017
19:36:19
@angmarr https://github.com/fsharp/fslang-suggestions/issues/506
Я просто вспомнил что в Scala есть что-то похоже, там вообще жесткий синтаксис на сокращение лябмд

Roman
29.03.2017
19:39:40
Чет не очень предложение ?
ну так да) Это я к тому, что не в паре символов счастье)

Arseniy
29.03.2017
19:40:47
Так можно и до какого-нибудь J докатится

Igor
29.03.2017
19:42:34
ну так да) Это я к тому, что не в паре символов счастье)
Ну когда у тебя весь код состоит из |> (fun x -> x...) - задумаешься

Roman
29.03.2017
19:43:15
Ну когда у тебя весь код состоит из |> (fun x -> x...) - задумаешься
надо просто использовать именованные ф-ции по мне так

Evgeniy
29.03.2017
19:43:44
+

Roman
29.03.2017
19:43:54
хотя да, иногда подбешивает fun , но в целом нормально)

Vasily
29.03.2017
19:46:47
list |> List.maxOf (fun x -> x.Id) как-то так
Тогда уж let id x=x.Id list|>List.maxBy id

Google
Nikolay
29.03.2017
19:48:01
https://gist.github.com/Dolfik1/1b7957240813eff28c161c3572203a72

Это ужасно, да?

Vasily
29.03.2017
19:48:56
Как-то в шарповом стиле,я бы сказал

Roman
29.03.2017
19:49:02
а почему ты не хочешь воспользоваться событиями?

Igor
29.03.2017
19:49:24
Nikolay
29.03.2017
19:49:47
а почему ты не хочешь воспользоваться событиями?
Я пока пытаюсь в целом раздуплиться как это делается

GNU/Patchouli
29.03.2017
19:49:48
Рекурсию надо.

Roman
29.03.2017
19:50:09
Я пока пытаюсь в целом раздуплиться как это делается
не, я про библиотеку которую ты используешь.

Igor
29.03.2017
19:50:37
Рекурсию надо.
Но только хвостовую ?

Nikolay
29.03.2017
19:51:46
не, я про библиотеку которую ты используешь.
Не совсем понимаю о чём речь, у меня пока только библиотека бот апи используется, больше ничего не цеплял

Vasily
29.03.2017
19:52:22
Там seq.filterby,seq.iter хватит

Ну и try надо преобразовывать,конечно

Nikolay
29.03.2017
19:53:15
вот в ней и есть события
А, ты про Telegram.Bot видимо, она кривовата

Igor
29.03.2017
19:53:48
вот в ней и есть события
Ты уверен, я не нашел (может конечно плохо искал)

Roman
29.03.2017
19:54:08
Nikolay
29.03.2017
19:54:13
В ней проблема с переиспользованием HttpClient

https://github.com/MrRoundRobin/telegram.bot/issues/281

Разработчик не фиксит, PR не принимает, поэтому забил на неё

Страница 19 из 772