Подтвердить что ты не робот

F # vs С# vs Nemerle

Получил новый проект в моем TODO и не может выбрать F # или Nemerle.

В настоящее время я изучаю F # и имею некоторые проекты на Nemerle.

Мне нравится F # way, мне нравится отступ по умолчанию (также я хочу отступать по умолчанию для nemerle2), мне нравятся многие функции и магия F #, но макросов нет.

Целью F # является VS2010 и, может быть, (возможно) более крупная команда разработчиков, и она выглядит как Haskell (может создавать легкие программы Linux с ней, и это весело).

Цель Nemerle - это макросы, и я думаю, что мне больше нравится синтаксис Nemerle.

и большинство людей просто как С#...

  • Таким образом, язык должен быть перспективным.
  • Синтаксис должен быть логичным, простым понимать, аккуратно и мощно (меньше код)
  • Он должен быть простым в использовании с .NET
  • Итак, я уже закрыл себя выбрал из этих трех.
  • Я могу использовать их все, кроме как выбрать. Мне это не так легко.

просто, например, мне нравится (Nemerle)

match(STT)
    | 1 with st= "Summ"
    | 2 with st= "AVG" =>
        $"$st : $(summbycol(counter,STT))"

намного больше (F #)

let (|Let|) v e = (v, e)

match stt with 
| Let "Summ" (st, 1) 
| Let "AVG" (st, 2) -> srintf "%s ..." st

F #:

["A"; "B"] |> List.iter (fun s  -> printfn "%d"  s.Length)

Nemerle:

["A", "B"].Iter(x => printf("%d", x.Length))

F # (надеюсь, что не ошибаюсь здесь):

let type X =
    let mytable a = ""
    let mytable b = ""
    new(A, B) = {
    a <- A
    b <- B }
    member X.A 
        with get  = a
    member X.B 
        with get  = a

Nemerle:

[Record]
class X
  public A : string { get; }
  public B : string { get; }

С#:

class X
{
    private readonly string _a;
    public string A { get { return _a; } }

    private readonly string _b;
    public string B { get { return _b; } }

    public X(string a, string b)
    {
        _a = a;
        _b = b;
    }
}

и вот код немерского я уже не могу преобразовать в F # (так что я только его изучаю)...

abstract class ABase
    abstract public A : string { get; }

interface IB
    B : string { get; }

[Record]
class My : ABase, IB
    public override A : string { get; }
    public virtual  B : string { get; }

Сравнение с С#:

abstract class ABase
{
    abstract public string A { get; }
}

interface IB
{
    string B { get; }
}

class My : ABase, IB
{
    private readonly string _a;
    public override A : string { get { return _a; } }

    private readonly string _b;
    public virtual  B : string { get { return _b; } }

    public My(string a, string b)
    {
        _a = a;
        _b = b;
    }
}

Очевидно, что код Nemerle легче поддерживать и читать более легко.

@Brian Итак, почему я спрашиваю, покажите мне, действительно ли это сделать проще на F #, С#, также если вы видите, что я делаю это неправильно, потому что я не уверен в других способах чтобы сделать то же самое.

4b9b3361

Ответ 1

F # и версии Nemerle совершенно разные:

  • Nemerle определяет класс, а F # определяет struct.
  • Nemerle определяет члены readonly, а F # определяет изменяемые члены.
  • Nemerle определяет публичные свойства, а F # определяет общедоступные поля.
  • Nemerle определяет конструктор, а F # не определяет его.

Аналогичный код Nemerle для примера F # следующий:

struct X
  mutable A : string
  mutable B : string

Второй пример почти тот же:

  • Nemerle определяет конструктор для My, а F # не определяет его.
  • Nemerle определяет свойства, возвращающие значение, переданное в конструкторе, а F # определяет свойства с постоянными значениями.

Версия Nemerle намного короче и яснее версии F # здесь.

P.S. О фигурных скобках и синтаксисе отступа. Nemerle поддерживает оба синтаксиса.

Вы можете написать либо:

class M
{
  static Main() : void
  {
    Console.WriteLine("A");
  }
}

Или используйте отступ:

#pragma indent
class M
  static Main() : void
      Console.WriteLine("A");

Или даже используйте оба стиля!

#pragma indent
class M
  static Main() : void { Console.WriteLine("A"); }

Ответ 2

показать мне, если это реально сделать это easer на F #, С# также, если вы видите, что я делаю это неправильно, потому что я не уверен в другие способы сделать то же самое.

Примеры F # и С# не очень кратки. Перепишите некоторые из примеров в OP:

Соответствие шаблону

Nemerle:

match(STT)
    | 1 with st= "Summ"
    | 2 with st= "AVG" =>
        $"$st : $(summbycol(counter,STT))"

F #:

Я не уверен на 100%, что вы делаете, но похоже, что он основан на этом ответе. Я не думаю, что легко создать новые переменные в выражении соответствия, но я думаю, что активные шаблоны переполнены.

Я бы написал код следующим образом:

let st = match stt with 1 -> "Summ" | 2 -> "Avg"
sprintf "%s ..." st

Карты тоже работают:

let sttMap = [1, "Summ"; 2, "Avg"] |> Map.ofList
sprintf "%s ..." (sttMap.[stt])

I <3 Предложение Jon:

let 1, st, _ | 2, _, st = stt, "Summ", "AVG"

Запись

Nemerle:

[Record]
class X
  public A : string { get; }
  public B : string { get; }

F #:

type X = { A : string; B : string }

С#:

class X {
    public string A { get; private set; }
    public string B { get; private set; }

    public X(string a, string b) {
        A = a;
        B = b;
    }
}

Классы

Nemerle

abstract class ABase
    abstract public A : string { get; }

interface IB
    B : string { get; }

[Record]
class My : ABase, IB
    public override A : string { get; }
    public virtual  B : string { get; }

F #:

[<AbstractClass>]
type ABase() =
    abstract member A : string

type IB =
    abstract member B : string

type My(a, b) =
    inherit ABase()
    override this.A = a

    abstract member B : string
    default this.B = b
    interface IB with
        member this.B = this.B

Некоторые примечания здесь:

  • Интерфейсы F # определяются с помощью ключевого слова abstract. Вы можете превратить их в абстрактные классы, используя атрибут [<AbstractClass>].

  • Интерфейсы реализованы явно. Как правило, вам нужно передать объект в определение интерфейса для вызова элементов интерфейса: let x = My("a", "b"); printf "%s" (x :> IB).B. Чтобы избежать приведения, вам нужно создать публичные элементы, которые отражают ваши методы интерфейса.

  • Виртуальные функции определяют abstract member с реализацией default.

Вы объединяете все эти компоненты и получаете определения классов, которые вредны для глазных нервов. Но это нормально, поскольку классы обычно не используются очень часто. Большинство объектных моделей F # определяются через объединения и записи; где классы используются, иерархии классов очень плоские, а не глубокие, поэтому вы не видите наследование или виртуальные функции, которые часто используются в F #, чем С#.

С#:

abstract class ABase {
    public abstract string A { get; }
}

interface IB {
    string B { get; }
}

class My : ABase, IB {
    public override string A { get; private set; }
    public virtual string B { get; private set; }

    public My(string a, string b) {
        A = a;
        B = b;
    }
}

Короче говоря, я думаю, что F # довольно сопоставим с Nemerle, но похоже, что вы просто изучаете его. Не волнуйтесь, когда я учился F #, я писал уродливый, громоздкий код, который в основном отражал С# с более забавным синтаксисом. Прошло немного времени, прежде чем я смог написать более идиоматически.

Я рекомендую следующее:

  • Если вы знакомы с Nemerle и используете его, продолжайте делать это:)
  • Если вы хотите узнать F #, я думаю, что ваш проект - хорошее место для начала. Я думаю, вы можете написать F # как чистую или лучше, чем ваш Nemerle.
  • С# тоже в порядке, но я бы не предпочел бы его по любому из языков, если вы выполняете много шаблонов или обработку символов.

Ответ 3

Синтаксис записи F # -

type X = { 
    A : string
    B : string 
}

Что касается кода, вы не можете конвертировать

[<AbstractClass>]
type ABase() =
    abstract A : string

type IB = 
    abstract B : string

type MyClass(a, b) = 
    inherit ABase()
        override this.A = a
    interface IB with 
        member this.B = b

Я не слишком уверен, что ваш пример соответствия шаблону пытается сделать, но F # имеет синтаксис (я думаю, что вы ищете)

match (STT) with
    | 1 when st = "Sum" -> ...
    | 2 when st = "Avg" -> ...

Ответ 4

F # имеют лучший синтаксис записи:

type X = struct
  val mutable A : string
  val mutable B : string
end

и есть ваш код, преобразованный в F #:

[<AbstractClass>] 
type ABase = 
    abstract member A : string
    // you can declare default implementation using default keyword like this:
    // default this.A with get () = "default implementation"

type IB =
    interface
        abstract member B : string
    end

type My = class
    inherit ABase
        override my.A with get() = "A"
    interface IB with
        member my.B with get() = "B"
end

Ответ 5

Преобразование кода, опубликованное Sparkie, немного неверно для преобразования С#, поскольку свойство B не является виртуальным и непосредственно не отображается в экземплярах типа My (вам нужно передать экземпляры в IB для доступа к B). Здесь более верное обращение:

[<AbstractClass>]
type ABase() =
    abstract A: string

type IB =
    abstract B: string

type My(a, b) =
    inherit ABase()

    override this.A = a

    abstract B: string
    default this.B = b

    interface IB with
        member this.B = this.B

Одно замечание, если вы новичок в F #: эта ссылка, переданная реализациям членов интерфейса, относится к типу объявляющего класса, поэтому (в приведенном выше примере) реализация IB в B ссылается на свойство B, объявленное в класс.

Ответ 6

Если вам нравятся оба языка, почему бы не смешать их? Вы можете создавать некоторые библиотеки в Nemerle, используя макросы и другие в F # для всего остального. Разве это не одно из преимуществ использования управляемой среды выполнения?: D

Затем вы можете создать пользовательский интерфейс (если есть), используя более удобный для него язык, такой как С# или VB.NET.

И как только вы решите добавить поддержку скриптов к своему продукту, вы можете использовать IronPython/IronRuby!

Я понимаю, что поддержка Nemerle IDE работает только в VS2008 (но поддерживает .net3.5 и 4.0), а F # работает как в VS2010, так и VS2008, поэтому, помимо различий в синтаксисе, он считает, что ваше решение также должно учитывать, что, в котором вы будете использовать IDE.

Ответ 7

Другое сравнение.

с использованием ключевого слова:

F #

use x = X()
use y = Y()
use z = Z()
...

Nemerle:

using (o = SomeType())
  ...

using (x = X())
using (y = Y())
using (z = Z())
  ... 

Форматирование строк:

F #:

let a = 1
let b = "x"
sprintf "%d %s" (a + 1) b

Nemerle:

def a = 1;
def b = "x";
def c = Nemerle.IO.sprintf("%d %s", a + 1, b);

Строковая интерполяция:

Имеет ли F # эту функцию?

Nemerle:

def a = 1;
def b = "x";
def c = $"$(a + 1) - $b"; // 0 - x

ключевое слово foreach: F #:

let list1 = [ 1; 5; 100; 450; 788 ]
for i in list1 do
  printfn "%d" i

let list1 = [ 1; 5; 100; 450; 788 ]
Seq.iteri (printfn "%d - %d")

let list1 = [ 1; 5; 100; 450; 788 ]
Seq.iteri (fun i x -> if i > 10 then printfn "%d - %d" i x)

let list1 = [ 1; 5; 100; 450; 788 ]
for x in list1 do
  printf "%s" (if x > 10 then printf "A"
               elif x < 10 then printf "B"
               elif "C"

Nemerle:

def list1 = [ 1, 5, 100, 450, 788 ]
foreach (i in list1)
  WriteLine($"$i")

def list1 = [ 1, 5, 100, 450, 788 ]
foreach (i in list1 with index) // index has an index of item. works for any collection.
  WriteLine($"$index - $i")

def list1 = [ 1, 5, 100, 450, 788 ]
foreach (i when i > 10 in list1 with index) // Pattern in foreach
  WriteLine($"$index - $i")

def list1 = [ 1, 5, 100, 450, 788 ]
foreach (_ in list1) // Implicit match
  | i when i > 10 => WriteLine("A")
  | i when i < 10 => WriteLine("B")
  | _ => WriteLine("C")

foreach (_ in [])
  | i when i > 10 => WriteLine("A")
  | i when i < 10 => WriteLine("B")
  | _ => WriteLine("C")
otherwise // Otherwise is taken when there were no iterations
  WriteLine("X")

Ответ 8

"Очевидно, что код Nemerle легче поддерживать и читаем".

Легче поддерживать кого?

Более читаемым для кого?

На чем вы основываете это суждение, отличное от вашего собственного опыта языка и ваших личных предубеждений? Я кодировал в С++ в течение многих лет, и поэтому я нахожу любой язык, который не использует фигурные скобки, чтобы разделить блоки кода на несколько интуитивно понятных. Но другие люди, которые закодированы на языках Lisp (или Lisp), вероятно, найдут понятие использования фигурных фигурных скобок очень странным и, следовательно, контринтуитивным. Люди, закодированные на языках Pascal или Pascal, скорее предпочтут "начать" и "закончить", чтобы разделить блоки кода - они обнаружат, что "легче поддерживать и читать".

Есть ли у вас какие-либо исследования, которые доказывают, что понимание кода выше с синтаксисом Nemerle, чем F # или С#? Потому что это будет единственная эмпирическая, объективная мера, о которой я могу думать, которая докажет, что код Nemerle "легче поддерживать и читать".

Для профессионального разработчика это всего лишь три разных синтаксиса. Если вы не сравниваете какой-либо язык с Brainf * ck, в основном это просто вопрос о том, какой синтаксис вы уже использовали и как долго вы должны изучить новую синтаксическую структуру.