Как стать автором
Обновить

Комментарии 22

недавно

6 лет назад.

Именно интерполяцию вида


let name = "Phillip"
let age = 30

printfn $"Name: {name}, Age: {age}"
printfn $"I think {3.0 + 0.14} is close to {System.Math.PI}!"

добавили недавно, в F# 5:
https://devblogs.microsoft.com/dotnet/announcing-f-5/

Код не меняется, меняется только твое восприятие. Но это я так, шучу)

я даже в Фотошоп полез это проверять, наложением скриншотов )))

UPD: Второй кусок кода поправили, но там теперь отсутствует упоминание HaveWings ¯\_(ツ)_/¯

Стало похоже на Elixir на минималках, имхо.

Код зависит от последовательности определения полей в таблице БД? Чёт как-то жёстко, но возможно я просто не понимаю это всё.

После F# остались только негативные эмоции. Размытый неконсистентный синтаксис, неуклюжий компилятор, миллион операторов, которые никто не подсказывает, язык постоянно лезет не в свое дело. Одно отсутствие циклического импорта чего стоит.
После Swift язык ощущается как ужасный самопал. В Swift для тех же Option придумали if case, if let, guard let, switch, optional chaining, optional init, implicitly unwrapped, все чтобы помочь программисту. В F#, насколько я понял, это только switch, который раздувает код. При этом в Swift value type это правда value type, а тут кто-то вернул из .NET record и пробуй обработать null, тебе пишут, что record не может быть null, ну да ну да. В Swift такие вещи маппятся в optional и никаких вопросов.
Или те же коллекции, которые не ведут себя как в .NET. Ну сделайте свой пакет коллекций, в чем проблема-то? Везде одни проблемы с этим языком.

это только switch, который раздувает код

Есть же ещё конструкции наподобие TaskBuilder и MaybeBuilder, которые позволяют делать optional и task chaining, но через переменные — как раз чтобы не обкладывать всё конструкциями match:


let onHello context =
  maybe {
    let! message = context.Update.Message
    let! name = message.Chat.FirstName
    sprintf "Hello, %s!" name
    |> sendMessage message.Chat.Id
  } |> ignore

Здесь, context.Update.Message — это Option<Message>. Аналогично с FirstName. В случае maybe после let! произойдён early return, если в option лежит None.

"...Swift для тех же Option придумали… В F#, насколько я понял, это только switch, который раздувает код..."
Если какая-то switch-логика уже упакована в функции (особенно стандартные), то switch не нужен:
let t1 = Some("test")
t1 |> Option.map(printfn "%A is mapped")
t1 |> Option.filter(fun t -> t.Length>5) |> Option.map(printfn "%A is mapped again")

Мне Swift тоже нравится, но он тоже мягко говоря раздут операторами, делающими одно и то же

Хм, не такой уж умный компилятор???? Или все же автор статьи не понял как задаются типы, в примере `let splitPath inputObject: string ` string задает тип функции, а не параметра. А надо вот так: `let splitPath (inputObject: string) = `…
Тут неясно, что мешает компилятору определить с чем он имеет дело, кортежи явно указываются как кортежи и две палки со стрелочкой рядом с ними выглядят избыточно.

А если функция принимает кортеж? А если функция полиморфна? Невозможно это определять компилятором в общем случае.


оказывается, компилятор не смог определить, что имеет дело со строкой из типа входного объекта.

А как он это поймет, метод Split может быть у чего угодно, тип никак не указан, а каких-нибудь анонимных интерфейсов насколько я знаю в языке нет (чтобы у аргумента был тип "любой тип, который содержит метод Split")
достаточно было просто указать тип аргументу


Абсолютно не понятно, зачем писать так:


let splitPath inputObject = 
  let mutable inputObject : string = inputObject
  ...

когда можно просто так:


let splitPath (inputObject: string) = 
  ...
А как он это поймет, метод Split может быть у чего угодно, тип никак не указан, а каких-нибудь анонимных интерфейсов насколько я знаю в языке нет (чтобы у аргумента был тип «любой тип, который содержит метод Split»)
Можно поизвращаться и написать функцию, принимающую что угодно, имеющее метод Split, но кроме строк его ни у кого нет, так что это лишено смысла.
let inline splitPath path =
    (^t: (member Split: char array -> string array) (path, [|'\\'; '/'|]))

По поводу кода, f# не знаю, но на хаскеле было бы так:


splitPath :: Text -> Text
splitPath = Text.intercalate "/" . init . Text.splitOn "/"

подозреваю что на f# примерно так же, смог написать только так:


let init xs = Seq.take (Seq.length xs - 1) xs

let splitPath (path: string) = 
  path.Split "/" |> init |> String.concat "/"

printf "%s" (splitPath "C:/users/test/folder")
Автор, я, конечно, всё понимаю, но ваш первый пример на F# выглядит вот так:
@"C:\Users\test\folder".Split '\\' |> (Seq.rev >> Seq.skip 1 >> Seq.rev >> String.concat "\\")
Или вот так, если использовать индексирование:
let s = @"C:\Users\test\folder" in s.[.. s |> Seq.findIndexBack ((=) '\\')]
Не надо пытаться писать на ML-подобном языке в императивном стиле, это в принципе возможно, но получается очень страшно.
НЛО прилетело и опубликовало эту надпись здесь
Не такой уж и умный компилятор

Оказывается, компилятор не смог определить, что имеет дело со строкой из типа входного объекта.

Но вы и не указали тип входного параметра. Вы указали возвращаемый тип — string.
Тип входного параметра указывается так:


let splitPath (inputObject : string) : string =

Вот так этот велосипед выглядит на Powershell:

$Path = «C:\users\test\folder»
$Trimer = $Path.Split(«\»)[$Path.Split(«\»).Count — 1]
$Path.Trim($Trimer)

Во-первых, велосипед можно сделать по-красивее

$Path = 'C:\users\test\folder'
$Path.Trim($Path.Split('\')[-1])

Во-вторых, даже тестовая задача должна иметь какой-то смысл.
Удалить из полного пути папки символы 'd', 'e', 'f', 'l', 'o', 'r' — не представляю, где это может пригодиться.
Напомню, метод Trim(Char[]) удаляет все начальные и конечные вхождения набора символов, указанного в массиве, из текущей строки.
В-третьих, в F# это выглядит так же красиво без всяких мутабельных переменных
let path = @"C:\users\test\folder"
let myTrim (str: string) = 
    str.Trim((str.Split('\\') |> Array.last).ToCharArray())
myTrim path

А System.IO.Path.DirectorySeparatorChar можно и в Powershell вставить
$Path.Trim($Path.Split([System.IO.Path]::DirectorySeparatorChar)[-1])
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.