Форум программистов, компьютерный форум, киберфорум
Наши страницы
Haskell
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
1

Повторяющийся код

20.05.2018, 02:44. Просмотров 1087. Ответов 20

Есть у меня следующий код

Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
data Command                                                                                                                                                                                                                                              
  = Fetch Pkg                                                                                                                                                                                                                                             
  | Unpack Pkg                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
  | Configure Pkg                                                                                                                                                                                                                                         
  | Compile Pkg                                                                                                                                                                                                                                           
  | Install Pkg
 
type Pkg = String                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                          
fetch :: Parser Command                                                                                                                                                                                                                                   
fetch =                                                                                                                                                                                                                                                   
  Fetch <$>                                                                                                                                                                                                                                               
  strOption                                                                                                                                                                                                                                               
    (long "fetch" <> short 'f' <> metavar "ebuild" <> help "fetch ebuild")                                                                                                                                                                                
                                                                                                                                                                                                                                                          
unpack :: Parser Command                                                                                                                                                                                                                                  
unpack =                                                                                                                                                                                                                                                  
  Unpack <$>                                                                                                                                                                                                                                              
  strOption                                                                                                                                                                                                                                               
    (long "unpack" <> short 'u' <> metavar "ebuild" <> help "unpack ebuild")                                                                                                                                                                              
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
configure :: Parser Command                                                                                                                                                                                                                               
configure =                                                                                                                                                                                                                                               
  Configure <$>                                                                                                                                                                                                                                           
  strOption                                                                                                                                                                                                                                               
    (long "configure" <> short 'c' <> metavar "ebuild" <> help "configure ebuild")                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                          
compile :: Parser Command                                                                                                                                                                                                                                 
compile =                                                                                                                                                                                                                                                 
  Compile <$>                                                                                                                                                                                                                                             
  strOption                                                                                                                                                                                                                                               
    (long "compile" <> short 'b' <> metavar "ebuild" <> help "compile ebuild")                                                                                                                                                                            
                                                                                                                                                                                                                                                          
install :: Parser Command                                                                                                                                                                                                                                 
install =                                                                                                                                                                                                                                                 
  Install <$>                                                                                                                                                                                                                                             
  strOption                                                                                                                                                                                                                                               
    (long "install" <> short 'i' <> metavar "ebuild" <> help "install ebuild")
Видно, что код имеет повторяющуюся структуру, а именно функции практически одинаковы, и я хочу его компактифицировать, чтобы эту структуру каждый раз не повторять, пока знаний haskell не хватает. Как наиболее просто его компактифицировать в haskell, что именно использовать?
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.05.2018, 02:44
Ответы с готовыми решениями:

Повторяющийся код
Здравствуй, уважаемые форумчане! Я нуб в написании кода, поэтому прощу помощи. ближе к делу....

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

Как упростить повторяющийся код
Всем добрый вечер. Есть два куска кода, которые отвечают за автокоплит допустим городов и улиц. У...

Повторяющийся код, как сделать короче?
Ребят, являюсь очень новичком в пхп. Встретился с проблемой где нужно удалить повторяющийся код, и...

Как лучше вынести повторяющийся код?
Есть некоторый код который повторяется в разных методах, хоть он и небольшой, но это начинает...

20
Catstail
Модератор
24829 / 12624 / 2305
Регистрация: 12.02.2012
Сообщений: 20,542
20.05.2018, 07:38 2
Как вариант:

Haskell
1
2
3
4
5
6
7
8
9
10
11
12
uCommand :: String -> Parser Command
uCommand "fetch"     = Fetch  <$> strOption (long "fetch" <> short 'f' <> metavar "ebuild" <> help "fetch ebuild")
uCommand "unpack"    = Unpack <$> strOption (long "unpack" <> short 'u' <> metavar "ebuild" <> help "unpack ebuild")
uCommand "configure" = Configure <$> strOption (long "configure" <> short 'c' <> metavar "ebuild" <> help "configure ebuild")
uCommand "compile"   = Compile <$> strOption (long "compile" <> short 'b' <> metavar "ebuild" <> help "compile ebuild")
uCommand "install"   = Install <$> strOption (long "install" <> short 'i' <> metavar "ebuild" <> help "install ebuild")
 
fetch = uCommand "fetch"
unpack = uCommand "unpack"
configure = uCommand "configure"
compile = uCommand "compile"
install = uCommand "install"
0
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
20.05.2018, 07:44  [ТС] 3
Хм, а разве кода не стало больше? Так как добавилось к тому коду, что был, еще кусок

Haskell
1
2
3
4
5
fetch = uCommand "fetch"
unpack = uCommand "unpack"
configure = uCommand "configure"
compile = uCommand "compile"
install = uCommand "install"
К тому же повторяющийся код никуда не делся. Пока думаю попробовать использовать fold.
0
Curry
2991 / 2072 / 257
Регистрация: 01.06.2013
Сообщений: 4,525
Записей в блоге: 9
20.05.2018, 08:00 4
Лучший ответ Сообщение было отмечено hardentoo как решение

Решение

Haskell
1
2
3
4
5
6
7
8
9
10
uCommand :: (Pkg -> Command) ->  Pkg -> Char -> Pkg -> Pkg -> Parser Command
uCommand f sVerb c sVar sHelp = 
  f <$>                                                                                                                                                                                                                                             
  strOption                                                                                                                                                                                                                                               
    (long sVerb <> short c <> metavar sVar <> help sHelp)
 
fetch :: Parser Command                                                                                                                                                                                                                                   
fetch =  uCommand Fetch "fetch" 'f' "ebuild" "fetch ebuild"
 
-- ...
3
20.05.2018, 08:00
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
20.05.2018, 08:09  [ТС] 5
То есть строится функция высшего порядка, пользуясь тем, что Command сумма типов с одинаковым kind? Осталось применить zipWith и повторяющегося кода не будет вовсе.
0
Curry
2991 / 2072 / 257
Регистрация: 01.06.2013
Сообщений: 4,525
Записей в блоге: 9
20.05.2018, 08:42 6
hardentoo, я вам привёл модификацию приведённого вами фрагмента кода где повторяющегося кода уже нет.
А дальше вы что то делаете с функциями из приведённого вами фрагмента, но что вы не привели. По этому и я не привожу вариант с zipWith (<|>).
Как я понимаю, вы используете пакет optparse-applicative.
0
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
20.05.2018, 09:05  [ТС] 7
Про zipWith я думал о чем-то таком
Haskell
1
zipWith uCommand [Fetch, ...] [ ["fetch", "f", ...],...]
но я не знаю как красиво присвоить имена fetch и т.д. элементам результирующего списка без использования индексации.
0
XRuZzz
Антикодер
1683 / 786 / 46
Регистрация: 15.09.2012
Сообщений: 2,898
20.05.2018, 10:29 8
Лучший ответ Сообщение было отмечено hardentoo как решение

Решение

Возможно идея будет полезной:
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module Common.Options (Command(..), uCommand) where
 
import Data.Char(toLower)
import Options.Applicative
import Data.Semigroup((<>))
 
data Command = Fetch Pkg
        | Unpack Pkg
        | Configure Pkg
        | Compile Pkg
        | Install Pkg
    deriving Show
 
type Pkg = String
 
getName :: (Pkg -> Command) -> String
getName f = map toLower . head . words. show $ f ""
 
uCommand :: (Pkg -> Command) -> Parser Command                                                                                                                                                                                                                                   
uCommand f =
    let
        optName = getName f
        helpS = optName ++ " ebuild"
    in f <$>
    strOption                           -- strOption :: Mod OptionFields Command -> Parser Command
        (long optName <> short (head optName) <> metavar "ebuild" <> help helpS)
Дока optparse-applicative довольно подробно написана, возможно в ней есть более интересные приёмы.

Не по теме:


Интересно, является ли optparse-applicative лучшим решением для опций?

2
Curry
2991 / 2072 / 257
Регистрация: 01.06.2013
Сообщений: 4,525
Записей в блоге: 9
20.05.2018, 10:30 9
hardentoo, по смыслу должна предполагаться только одна команда, а не fetch и compile одновременно.
Если средствами optparse-applicative допускать несколько вариантов одновременно, то
Haskell
1
2
3
4
    some ( uCommand аргументы
       <|> uCommand аргументы
       <|> uCommand аргументы
         )
- получите список.
0
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
21.05.2018, 01:23  [ТС] 10
Я говорил именно про изначальный код, вот что пока вышло

Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
data Command
  = Fetch Pkg
  | Unpack Pkg
  | Prepare Pkg
  | Configure Pkg
  | Compile Pkg
  | Install Pkg
 
type Pkg = String
 
apply func optionList = func <$> opt optionList
  where
    opt [longOpts, shortOpts, metavarOpts, helpOpts] =
      strOption
        (long longOpts <> short (head shortOpts) <> metavar metavarOpts <>
         help helpOpts)
 
fetch = result !! 0
unpack = result !! 1
prepare = result !! 2
configure = result !! 3
compile = result !! 4
install = result !! 5
 
result =
  zipWith
    apply
    [Fetch, Unpack, Prepare, Configure, Compile, Install]
    [ ["fetch", "f", "ebuild", "fetch ebuild"]
    , ["unpack", "u", "ebuild", "unpack ebuild"]
    , ["prepare", "p", "ebuild", "prepare ebuild"]
    , ["configure", "c", "ebuild", "configure ebuild"]
    , ["compile", "b", "ebuild", "compile ebuild"]
    , ["install", "i", "ebuild", "install ebuild"]
    ]
Вот про этот zipWith шла речь, но вот этот кусок

Haskell
1
2
3
4
5
6
fetch = result !! 0
unpack = result !! 1
prepare = result !! 2
configure = result !! 3
compile = result !! 4
install = result !! 5
использует индексацию, и мне не нравится.
0
Curry
2991 / 2072 / 257
Регистрация: 01.06.2013
Сообщений: 4,525
Записей в блоге: 9
21.05.2018, 09:03 11
Цитата Сообщение от hardentoo Посмотреть сообщение
Я говорил именно про изначальный код
Между кодом из стартового поста и вашим новым общего первые 9 строк. Объясните что вы хотите.
Вы делаете список, потом к нему обращаетесь по индексам и это вам не нравится. Может быть вам не нужен список?
Цитата Сообщение от hardentoo Посмотреть сообщение
Вот про этот zipWith
Вы ориентируетесь на какие то другие языки где кроме списков ничего нет. Даже если бы вам требовался список команд, то формируя данные для apply уместно использовать запись или (хуже) просто конструктор данных с многими полями. А не выносить аргументы одного типа в список.
Haskell
1
2
3
4
data CommandInit = CommandInit { commandAction :: Pkg -> Command
                               , commandLongOpts :: Pkg
                               .....
                               }
1
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
21.05.2018, 09:22  [ТС] 12
Я хотел на простом примере понять какие есть способы в haskell избавиться от повторяющегося кода. Вариант с zipWith --- это вариант с по-настоящему без повторяющегося кода, а в примерах выше происходит вызов одной и той же функции с разными аргументами для конструирования однотипных функций (а повторяющиеся действия я думаю надо заменять на свертки или что-то похожее для компактности). А вот про записи я не подумал, может как-то можно используя записи обойтись без оператора (!!)?
0
Curry
2991 / 2072 / 257
Регистрация: 01.06.2013
Сообщений: 4,525
Записей в блоге: 9
21.05.2018, 10:21 13
Спор о том что повторяющийся код, а что нет - это для холиваров.
Цитата Сообщение от hardentoo Посмотреть сообщение
может как-то можно обойтись без оператора (!!)?
Вы так и не объяснили ЧТО ВЫ ХОТИТЕ ПОЛУЧИТЬ, а я не телепат. Вы пишите что (!!) вам не нравится. Мне тоже.
Ну, опишите тогда что может быть в командной строке вашей программы, а что нет. Типа хелпа по ваше утилите, только про командную строку.
0
Mysterious Light
Эксперт по математике/физике
4096 / 2005 / 410
Регистрация: 19.07.2009
Сообщений: 3,025
Записей в блоге: 22
21.05.2018, 11:44 14
Цитата Сообщение от hardentoo Посмотреть сообщение
А вот про записи я не подумал, может как-то можно используя записи обойтись без оператора (!!)?
Цитата Сообщение от hardentoo Посмотреть сообщение
Haskell
1
2
3
4
5
6
fetch = result !! 0
unpack = result !! 1
prepare = result !! 2
configure = result !! 3
compile = result !! 4
install = result !! 5
Может, обычное сопоставление с образцом?
Haskell
1
[fetch, unpack, prepare, configure, compile, install] = result
Хотя по моему мнению лучше использовать решение #4
0
Curry
2991 / 2072 / 257
Регистрация: 01.06.2013
Сообщений: 4,525
Записей в блоге: 9
21.05.2018, 13:09 15
Parser из вышеупомянутого пакета не монада, так что впрямую использовать что то вроде foldlM не выйдет.
Но в пакете есть ParserM который монада. Если заворачивать в него Parser-ы, то можно применить foldlM.
Не пробовал.
0
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
21.05.2018, 18:01  [ТС] 16
Цитата Сообщение от Mysterious Light Посмотреть сообщение
Может, обычное сопоставление с образцом?

Haskell
1
[fetch, unpack, prepare, configure, compile, install] = result
Именно так я и хотел изначально, но думал, что в haskell слева от оператора (=) нельзя писать выражения, и если так написать то ругается на error: parse error on input '['. (В какой-то книге читал, сейчас не смог найти, что раньше можно было писать например так fib (n+1) = fib n + fib (n-1), а теперь так нельзя и необходимо только, например fib n = fib (n-1) + fib (n-2)).

Вариантов написания было очень много, и видимо надо выбрать именно из ответа #4

Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Ну, опишите тогда что может быть в командной строке вашей программы, а что нет.
Программа принимает на вход --install pkgname (кратко -i pkgnme) или например --compile pkgname, причем принимает только одно действие.
Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Parser из вышеупомянутого пакета не монада,
Ах как интересно, я только собирался думать как их сделать монадами, так как хотелось иметь возможность писать например compile>>install.
0
Curry
2991 / 2072 / 257
Регистрация: 01.06.2013
Сообщений: 4,525
Записей в блоге: 9
21.05.2018, 18:57 17
Цитата Сообщение от hardentoo Посмотреть сообщение
Именно так я и хотел изначально, но думал, что в haskell слева от оператора (=) нельзя писать выражения, и если так написать то ругается на error: parse error on input '['.
Компилятор на что то другое ругался. Так вы уже писали - #10, строка 13. Ещё перед скобками тильду, что бы предупреждения не было - ~[....]. Но это плохой стиль - создавать списки фиксированной длины там где без них можно обойтись.
Цитата Сообщение от hardentoo Посмотреть сообщение
принимает только одно действие.
Тогда
Haskell
1
2
3
uCommand аргументы
       <|> uCommand аргументы
       <|> uCommand аргументы
и не парьтесь. Так в документации к пакету и рекомендуется.
Цитата Сообщение от hardentoo Посмотреть сообщение
Ах как интересно, я только собирался думать как их сделать монадами
Там есть функции oneM, fromM.
Цитата Сообщение от hardentoo Посмотреть сообщение
так как хотелось иметь возможность писать например compile>>install
А compile,install внутри (!!) будут содержать? А если нет, то чем это лучше примера кода в этом сообщении?
Я имел ввиду использовать монаду со свёрткой, если уж вам непременно нужны списки. в свёртке (<|>) использовать.
0
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
21.05.2018, 19:29  [ТС] 18
Цитата Сообщение от KolodeznyDiver Посмотреть сообщение
Так вы уже писали - #10, строка 13.
Там выражение в аргументе функции и знак = это определение 1 функции. Но я думаю, что если есть
Haskell
1
2
a=1
b=2
то переписать код выше используя только 1 знак равенства не получится, так как например
Haskell
1
[a,b]=[1,2]
неверно. Я был неправ. Только что провел эксперимент в ghci и оказывается [a,b]=[1,2] работает!!! Если сделать x=[a,b] и вывести x, то выводится [1,2]!
0
Curry
2991 / 2072 / 257
Регистрация: 01.06.2013
Сообщений: 4,525
Записей в блоге: 9
21.05.2018, 20:18 19
Цитата Сообщение от hardentoo Посмотреть сообщение
Только что провел эксперимент в ghci и оказывается [a,b]=[1,2] работает!!!
Жалко умалять радость от открытия, но, может быть учебник почитать?
1
hardentoo
127 / 26 / 1
Регистрация: 10.10.2017
Сообщений: 32
22.05.2018, 00:31  [ТС] 20
KolodeznyDiver, Учебник читаю.

Добавлено через 2 часа 40 минут
Окончательный вариант
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
data Command                                                                                                                                                                                                                                                     
  = Fetch Pkg                                                                                                                                                                                                                                                    
  | Unpack Pkg                                                                                                                                                                                                                                                   
  | Prepare Pkg                                                                                                                                                                                                                                                  
  | Configure Pkg                                                                                                                                                                                                                                                
  | Compile Pkg                                                                                                                                                                                                                                                  
  | Install Pkg                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
type Pkg = String                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                 
apply func optionList = func <$> opt optionList                                                                                                                                                                                                                  
  where                                                                                                                                                                                                                                                          
    opt [longOpts, shortOpts, metavarOpts, helpOpts] =                                                                                                                                                                                                           
      strOption                                                                                                                                                                                                                                                  
        (long longOpts <> short (head shortOpts) <> metavar metavarOpts <>                                                                                                                                                                                       
         help helpOpts)                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                 
[fetch, unpack, prepare, configure, compile, install] =                                                                                                                                                                                                          
  zipWith                                                                                                                                                                                                                                                        
    apply                                                                                                                                                                                                                                                        
    [Fetch, Unpack, Prepare, Configure, Compile, Install]                                                                                                                                                                                                        
    [ ["fetch", "f", "ebuild", "fetch ebuild"]                                                                                                                                                                                                                   
    , ["unpack", "u", "ebuild", "unpack ebuild"]                                                                                                                                                                                                                 
    , ["prepare", "p", "ebuild", "prepare ebuild"]                                                                                                                                                                                                               
    , ["configure", "c", "ebuild", "configure ebuild"]                                                                                                                                                                                                           
    , ["compile", "b", "ebuild", "compile ebuild"]                                                                                                                                                                                                               
    , ["install", "i", "ebuild", "install ebuild"]                                                                                                                                                                                                               
    ]
1
22.05.2018, 00:31
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.05.2018, 00:31

Как оптимизировать повторяющийся код html?
Есть такой код: &lt;div id=&quot;file0&quot; style=&quot;display:block&quot; onClick=&quot;vybor_object(this.id);...

Нужно повторяющийся код оформить функцией - что принимать параметром?
Пытаюсь написать тест на знание творчества Тургенева. Если ответ правильный - то он выделяется...

Запрет статического вызова или повторяющийся код в каждом методе
Доброго времени суток. Есть некий класс, который требует для работы дополнительные данные. Например...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.