LINUX.ORG.RU

Помогите нубу

 ,


0

2

Вопрос к адептам ФП. Чем можно заменить в ФП классы и нужно ли это вообще делать? Особенно интересно мнение знающих F# людей, нужны ли там классы или они являются скорее костылем, который вы заменяете на что-то?

Если очень сильно надо, можно реализовать ООП самому. На схеме это делается элементарно. В CL есть CLOS.

buddhist ★★★★★
()
Ответ на: комментарий от anonymous

А не могли бы Вы привести аналог этого кода на Haskell/ADT?

class Mushroom {
  public Mushroom(int size) {...} 
  public Mushroom() {...}
  public Mushroom(boolean isMagic) {...}
  public Mushroom(boolean isMagic, int size) {...}
}
anonymous
()

П.С. всё что есть - можно (и иногда нужно) использовать. Отказываться от каких-либо возможностей ЯП, на котором пишешь, это как отрезать себе руку «патамуфта крута».

Norgat ★★★★★
()
Ответ на: комментарий от anonymous

Ну да, лисперы никогда не фапали яростно на фп, как это делают хаскелисты.

buddhist ★★★★★
()
Ответ на: комментарий от anonymous

А не могли бы Вы привести аналог этого кода на Haskell/ADT?

Учитывая, что этот код не производит никаких действий, то за счёт ленивости он не будет даже вызван.

kim-roader ★★
()

Если тебя интересует инкапсуляция, то делаешь модуль Mushroom в котором делаешь тип data Mushroom = Mushroom SomeThing и кучу функций, которые с этим твоим мушрумом работают. Затем экспортируешь наружу функции и имя типа, но не экспортируешь конструкторы.

Если интересует полиморфизм, то тут используют… классы.

KblCb ★★★★★
()

Можешь использовать вместо классов замыкания. Правда есть шанс увлечься и случайно написать свою классовую систему.

anonymous
()
Ответ на: комментарий от Deleted

Посмотри на stl, много там ООПа? Классы там совсем не в ООП смысле используются, а как модули.

anonymous
()
Ответ на: комментарий от anonymous

А зачем? На Хаскелле был бы совершенно иной дизайн.

anonymous
()
Ответ на: комментарий от Norgat

Чушь. За все надо платить, и цена часто бывает неоправданной (как, например, с исключениями в плюсах).

anonymous
()
Ответ на: комментарий от KblCb

Я (аноним с грибамы) не ТС. Но меня тоже интересует чем заменить в Haskell ООП и можно ли там построить ООП поверх ADT. Я прочитал 2 главы из real world haskell, но не очень понял ADT.

Не могли бы вы привести полный аналог такого кода? (если я правильно понимаю, то в хаскеле он должен быть 3-4 раза короче)

class Mushroom {
  int size;
  boolean isMagic;

  public Mushroom(int s) {
    size = s;
    isMagic = false;
  }
 
  public Mushroom() {
    size = 0;
    isMagic = false;
  }

  public Mushroom(boolean magic) {
    size = 0;
    isMagic = magic;
  }
  
  public Mushroom(boolean magic, int s) {
    size = s;
    isMagic = magic;
  }

  public void info()
  {
    System.out.print("This mushroom is " + size + " inch high and it is ");
    if(isMagic) System.out.println("magic");
    else System.out.println("not magic");
  }
}

public class MushroomTest
{
  public static void main(String[] args)
  {
    Mushroom m1 = new Mushroom();
    m1.info();

    Mushroom m2 = new Mushroom(true, 20);
    m2.info();

    Mushroom m3 = new Mushroom(42);
    m3.info();
  }
}

Спасибо.

p.s. капча which Manada

anonymous
()
Ответ на: комментарий от anonymous

За все надо платить, и цена часто бывает неоправданной (как, например, с исключениями в плюсах).

Если пихать исключения куда не следует, то да, будет бо-бо. Но никто не заставляет их использовать где не следует.

Norgat ★★★★★
()
Ответ на: комментарий от Norgat

То, что они есть я знаю. И пользуюсь ими. Просто стало интересно - а нужны ли они вообще в F# или реализованы в большей степени для поддержки другой парадигмы.

i_overdose
() автор топика
Ответ на: комментарий от i_overdose

Некоторые вещи проще сделать с помощью классов. Те же идеи полиморфизма бывают удобней чем аналоги на размеченных объединениях скажем.

Norgat ★★★★★
()
Ответ на: комментарий от anonymous
module Mushroom
    ( Mushroom
    , newMushroomWithSize
    , newMushroom
    , newMushroomWithMagic
    , newMushroomAny
    , info )
where

data Mushroom = Mushroom { size :: Integer, isMagic :: Bool }

newMushroomWithSize :: Integer -> Mushroom
newMushroomWithSize size = Mushroom size False

newMushroom :: Mushroom
newMushroom = Mushroom 0 False

newMushroomWithMagic :: Bool -> Mushroom
newMushroomWithMagic isMagic = Mushroom 0 isMagic

newMushroomAny :: Bool -> Integer -> Mushroom
newMushroomAny isMagic size = Mushroom size isMagic

info :: Mushroom -> IO ()
info m = do
    putStr ("This mushroom is " ++ show (size m) ++ "inch high and it is ")
    if isMagic m
        then putStrLn "magic"
        else putStrLn "not magic"

module Other where

import Mushroom

mushroomTest :: IO ()
mushroomTest = do
    info newMushroom
    info (newMushroomAny True 20)
    info (newMushroomWithSize 43)

Как-то так.

KblCb ★★★★★
()
Ответ на: комментарий от anonymous

В этом коде нет никакого смысла, так что сокращать тут нечего, а код по сути состоит из перегрузки функции и примитивной структуры с двумя полями. Но если ты так просишь, то с использованием record'ов можно написать что-то такое:

data Mushroom = Mushroom { size :: Integer
                         , isMagick :: Bool
                         } 
              deriving (Show, Eq)
                
mushroom = Mushroom {size = 0, isMagick = False}

info :: Mushroom -> IO ()
info m = 
  do { putStrLn $ "This mushroom is " ++ show (size m) ++ " inch high and it is " 
     ; if isMagick m 
       then putStrLn "magic" 
       else putStrLn "not magic"
     }
         
main = do { info $ mushroom
          ; info $ mushroom {isMagick = True, size = 20}
          ; info $ mushroom {size = 42}
          }

kim-roader ★★
()
Ответ на: комментарий от KblCb

В его коде основная идея это инкапсуляция

Всё впорядке, изменять поля созданной структуры всё равно невозможно, так что инкапсуляция не важна.

Точно также не важна модульность, поскольку класс слишком маленький и невыразительный и на полноценный модуль не тянет.

kim-roader ★★
()
Ответ на: комментарий от anonymous

Казалось бы, при чём тут ООП.

anonymous
()
Ответ на: комментарий от kim-roader

Всё впорядке, изменять поля созданной структуры всё равно невозможно, так что инкапсуляция не важна.

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

Можно написать код, который будет паттерн-матчить грибы по их кишочкам, юзать конструкции вроде foo' = foo { bar = baz } и прочие непотребства, таким образом завязываясь на детали внутренней, мать её, реализации объекта. И это будет уже ниразу не инкапсулировано.

anonymous
()
Ответ на: комментарий от anonymous

ФУТАКИМБЫТЬ!!!

Окай

data Mushroom = Mushroom { size :: Integer
                         , isMagick :: Bool
                         }
                
instance Show Mushroom where
  show m = "This mushroom is " ++ show (size m) ++ " inch high and it is " 
           ++ (if isMagick m then "magic" else "not magick")
                
mushroom = Mushroom {size = 0, isMagick = False}
         
main = do { print $ mushroom
          ; print $ mushroom {isMagick = True, size = 20}
          ; print $ mushroom {size = 42}
          }
kim-roader ★★
()
Ответ на: комментарий от anonymous
data Mushroom = Mushroom {size :: Int, isMagic :: Bool}

instance Show Mushroom where
  show (Mushroom s m) = "This mushroom is " ++ (show s) ++ " inch hight and it is "
                         ++ (if m then "magic" else "not magic")
                         
mushroom = Mushroom 0 False

m1 = mushroom
m2 = mushroom {size = 20, isMagic = True}
m3 = mushroom {size = 42}
anonymous
()
Ответ на: комментарий от anonymous

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

Хорошее сокрытие хорошо сочится через все конструкторы. Вообще код

type X = X{place :: Type}

ничем не отличается от

public class X { public Type place {get;} }

Но в случае если представление может серьёзно меняться и нужен красивый set, то конечно имеет смысл смотреть в расширяемые рекорды.

kim-roader ★★
()

все ответы в Concepts, Techniques, and Models of Computer Programming глава 7.

ответы про хаскель раньше в главе 4.

4.5.2 сравнение декларативных моделей. в том числе и хаскель.

dimon555 ★★★★★
()

классы в эф-шарп не нужны. вернее нужны - только для совместимости с дотНетом. а если быть точнее, то приходится создавать объекты библиотечных классов, но писать собственные классы - не приходится, максимум методы хешкода и сравнения переопределить, да и то для алгебраических типов данных.

kyz
()
Ответ на: комментарий от buddhist

а какое отношение смолтолк имеет к эф-шарпу?

kyz
()
Ответ на: комментарий от Norgat

да не в инкапсуляции дело, а вот в чем(цитата из книги по пистону):

# ООП
class A:
  def a(): ...
  def b(): ...
  def c(): ...
 
class B:
  def a(): ...
  def b(): ...
  def c(): ...
 
class C:
  def a(): ...
  def b(): ...
  def c(): ...
 
# процедурный подход
 
def a(x):
  if type(x) is A: ...
  if type(x) is B: ...
  if type(x) is C: ...
 
def b(x):
  if type(x) is A: ...
  if type(x) is B: ...
  if type(x) is C: ...
 
def c(x):
  if type(x) is A: ...
  if type(x) is B: ...
  if type(x) is C: ...

При внесении нового типа объекта изменения в ОО-программе затрагивают только один модуль, а в процедурной - все процедуры:

# ООП
 
class D:
  def a(): ...
  def b(): ...
  def c(): ...
 
# процедурный подход
 
def a(x):
  if type(x) is A: ...
  if type(x) is B: ...
  if type(x) is C: ...
  if type(x) is D: ...
 
def b(x):
  if type(x) is A: ...
  if type(x) is B: ...
  if type(x) is C: ...
  if type(x) is D: ...
 
def c(x):
  if type(x) is A: ...
  if type(x) is B: ...
  if type(x) is C: ...
  if type(x) is D: ...

И наоборот, теперь нужно добавить новый метод обработки. При процедурном подходе просто пишется новая процедура, а вот для объектного приходится изменять все классы:

# процедурный подход
 
def d(x):
  if type(x) is A: ...
  if type(x) is B: ...
  if type(x) is C: ...
 
# ООП
 
class A:
  def a(): ...
  def b(): ...
  def c(): ...
  def d(): ...
 
class B:
  def a(): ...
  def b(): ...
  def c(): ...
  def d(): ...
 
class C:
  def a(): ...
  def b(): ...
  def c(): ...
  def d(): ...

kyz
()
Ответ на: комментарий от anonymous

instance Show Mushroom where же.

Не надо так делать. class Show предназначен для такого вывода, который потом можно заReadить. kim-roader всё делал правильно.

Miguel ★★★★★
()

Особенно интересно мнение знающих F# людей, нужны ли там классы или они являются скорее костылем, который вы заменяете на что-то?

Конечно, нужны. F# - гибридный язык, как и Common Lisp, и Scala.

К тому же, классы можно очень красиво использовать с вычислительными выражениями, например, чтобы избавиться от избыточного вызова функции lift, когда значение в одной монаде автоматически поднимается до значения в другой. Мы просто две монады связываем отношением наследования, а тогда построители вычислительных выражений для таких монад сами разберутся, где и что использовать оптимальным образом. Без ООП этого изящно не сделать. Классы типов уже не помогают.

Вообще, гибридное программирование - очень интересная штука. Не стоит зацикливаться только на какой-то одной парадигме.

dave ★★★★★
()
Ответ на: комментарий от Miguel

Miguel

Не надо так делать. class Show предназначен для такого вывода, который потом можно заReadить. kim-roader всё делал правильно.

Он просто не написал соответствующий инстанс Read, лично я не считаю такой код неправильным.

unC0Rr ★★★★★
()
Ответ на: комментарий от anonymous

Именно по этому нормальные люди исключения и не используют.

trex6 ★★★★★
()
Ответ на: комментарий от kim-roader

Хорошее сокрытие хорошо сочится через все конструкторы

Так не экспортируй конструкторы!

anonymous
()
Ответ на: комментарий от Miguel

Не надо так делать. class Show предназначен для такого вывода, который потом можно заReadить

Это-то да, я просто указал на то, что функция, которая всего лишь переводит объект в текстовое представление, должна быть чистой, а не IO, как в исходном примере.

anonymous
()
Ответ на: комментарий от korvin_

Вполне нормальный, что тебе не нравится?

Кроме того, что тогда невозможно будет из другого модуля создать копию объекта? Замечательный план. Просто ограничивает приминимость кода.

kim-roader ★★
()
Ответ на: комментарий от kim-roader

Кроме того, что тогда невозможно будет из другого модуля создать копию объекта?

Хорош язык где для копирования нужен публичный конструктор.

belous_k_a
()
Ответ на: комментарий от kim-roader

Ты так говоришь, как буд-то в ооп метод копирования объекта можно написать где-то вне класса. И вообще, зачем в хаскелле что-то копировать?

korvin_ ★★★★★
()
Ответ на: комментарий от belous_k_a

Ты бы хоть немного с языком ознакомился, прежде чем что-то писать, а то слишком толсто/глупо выглядишь.

korvin_ ★★★★★
()
Ответ на: комментарий от anonymous

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

А, это точно, поддерживаю.

Miguel ★★★★★
()
Ответ на: комментарий от korvin_

Ты бы хоть немного с языком ознакомился

С тем который столь убог? Зачем, для работы он ненужен, для время препровождения есть Реальны Мир.

belous_k_a
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.