Критикуйте эту последнюю ночь, код новичка Haskell

Есть быстрый и грязный ответ и правильный ответ

Быстрый и грязный

Используйте list?.elementAt() ?? "" для безопасного доступа к элементу списка

Widget build(context) {
    try{
      if (isFirst == true) {
        fetchImage();
        fetchCategories(context);
        isFirst = false;
      }
    }catch(Exception){

    }

    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        appBar: AppBar(
          title: Text('Lets see images!'),
        ),
        body: new Column(
          children: [
            new Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                new InkResponse(
                    child: new Column(
                      children: [
                        Padding(
                          padding: EdgeInsets.all(10.0),
                          child: new Image.asset(
                            catimages?.elementAt(0) ?? "",
                            width: 60.0,
                            height: 60.0,
                          ),
                        ),
                        new Text(
                          categoriesText?.elementAt(0) ?? "",
                          style: TextStyle(color: Colors.white),
                        ),
                      ],
                    ),
                    onTap: () {
                      debugPrint("on tv clikced");
                      widget.fetchApI.fetchSubCategories(context, 6);
                    }),
                new InkResponse(
                  child: new Column(
                    children: [
                      Padding(
                        padding: EdgeInsets.all(10.0),
                        child: new Image.asset(
                          catimages?.elementAt(1) ?? "",
                          width: 60.0,
                          height: 60.0,
                        ),
                      ),
                      new Text(
                        categoriesText?.elementAt(1) ?? "",
                        style: TextStyle(color: Colors.white),
                      ),
                    ],
                  ),
                  onTap: () {
                    debugPrint("on moview clicked");
                    widget. fetchApI.fetchSubCategories(context, 7);
                  },
                ),
                new InkResponse(
                  child: new Column(
                    children: [
                      Padding(
                        padding: EdgeInsets.all(10.0),
                        child: new Image.asset(
                          catimages?.elementAt(2) ?? "",
                          width: 60.0,
                          height: 60.0,
                        ),
                      ),
                      new Text(
                       categoriesText?.elementAt(2) ?? "",
                        style: TextStyle(color: Colors.white),
                      ),
                    ],
                  ),
                  onTap: () {
                    debugPrint("on news clicked");
                    widget.fetchApI.fetchSubCategories(context, 10);
                  },
                ),
                new InkResponse(
                  child: new Column(
                    children: [
                      Padding(
                        padding: EdgeInsets.all(10.0),
                        child: new Image.asset(catimages?.elementAt(3) ?? "",
                            width: 60.0, height: 60.0),
                      ),
                      new Text(
                        categoriesText?.elementAt(3) ?? "",
                        style: TextStyle(color: Colors.white),
                      ),
                    ],
                  ),
                  onTap: () {
                    debugPrint('on shows clicked');
                    widget.fetchApI.fetchSubCategories(context, 8);
                  },
                ),
                new InkResponse(
                  child: new Column(
                    children: [
                      Padding(
                        padding: EdgeInsets.all(10.0),
                        child: new Image.asset('assets/live_icon.png',
                            width: 60.0, height: 60.0),
                      ),
                      new Text(
                        'Live',
                        style: TextStyle(color: Colors.white),
                      ),
                    ],
                  ),
                  onTap: () {
                    debugPrint('on live clicked');
                  },
                ),
              ],
            ),
            ImageList(images,widget.fetchApI),
          ],
        ),
      ),
    );
  }
}

Правильный ответ

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

Пожалуйста, используйте вместо этого FutureBuilder , StreamBuilder или ValueListenableBuilder , но вам нужно предоставить больше кода (особенно fetchImage и fetchCategories) для нас, чтобы помочь.

7
задан Guy Coder 15 December 2013 в 14:52
поделиться

5 ответов

I would first and foremost start using pattern-matching.

areListsEqual :: Eq a => [a] -> [a] -> Bool
areListsEqual [    ] [    ] = True
areListsEqual [    ] _      = False
areListsEqual _      [    ] = False
areListsEqual (x:xs) (y:ys) = x == y && areListsEqual xs ys

Note how much more readable this is, when head and tail is avoided.

charlieSort :: Eq a => [[a]] -> [[a]]
charlieSort    [                    ] = []
charlieSort    [x                   ] = [x]
charlieSort xs@(first:second:theRest)
  | areListsEqual xs wip              = wip
  | otherwise                         = charlieSort wip
  where
  swapPairIfNeeded a b
    | length a >= length b = [second,first]
    | otherwise            = [first,second]
  modifiedPair = swapPairIfNeeded first second
  wip = take 1 modifiedPair ++ charlieSort (drop 1 modifiedPair ++ theRest)

I changed the if-then-else to a guard for slightly improved readability (YMMV). Instead of checking that the list has at least two elements with a call to length we use pattern-matching, which also allows us to name first,second,theRest directly. The name @ pattern pattern both matches the input against pattern and names the whole input as name.

Now, I want to avoid using take and drop for extracting the two elements of modifiedPair, so the last two lines are changed into

  [shorter,longer] = swapPairIfNeeded first second
  wip = [shorter] ++ charlieSort ([longer] ++ theRest)

where you could write the last line as

  wip = shorter : charlieSort (longer : theRest)

if you preferred. But why should swapPairIfNeeded return the shorter and the longer of the first and second list in a list ? Why not use a pair like

  swapPairIfNeeded a b
    | length a >= length b = (second,first)
    | otherwise            = (first,second)
  (shorter,longer) = swapPairIfNeeded first second

? In most circumstances, it is better to use tuples for fixed number of values (possibly of differing types) and to use lists for variable number of values (necessarily of same type). But it seems strange that swapPairIfNeeded compares its arguments a and b, but then returns first and second anyway. In this case, instead of letting it return a and b in a pair, I will remove swapPairIfNeeded altogether instead :

  (shorter,longer)
    | length first >= length second = (second,first)
    | otherwise                     = (first,second)

"unfolding" the body of swapPairIfNeeded into the definition of (shorter,longer).

So now the code of charlieSort looks like

charlieSort :: Eq a => [[a]] -> [[a]]
charlieSort    [                    ] = []
charlieSort    [x                   ] = [x]
charlieSort xs@(first:second:theRest)
  | areListsEqual xs wip              = wip
  | otherwise                         = charlieSort wip
  where
  (shorter,longer)
    | length first >= length second = (second,first)
    | otherwise                     = (first,second)
  wip = shorter : charlieSort (longer : theRest)

Finally, I should remark that charlieSort doesn't really implement bubble-sort, because the recursive call to charlieSort will not only make one "bubble-up" pass along the list, but also fully sort the list longer : theRest, so that all that has to be done after this recursive call (before returning one "level up") is to possibly percolate shorter to its rightful place.

6
ответ дан 6 December 2019 в 15:31
поделиться

You don't need the areListsEqual function. You can compare lists with the (==) function. And I'd use a quicksort rather than bubblesort. Here's a solution that I think uses only what you should have learned so far.

charlieSort :: (Eq a) => [[a]] -> [[a]]
charlieSort []     = []
charlieSort (x:xs) = charlieSort (filter (cmpLen (>) x) xs) ++ [x] ++
                     charlieSort (filter (cmpLen (<=) x) xs)
   where filter _ [] = []
         filter p (x:xs) = (if (p x) then (x:) else id) (filter p xs)
         cmpLen f x y = f (length x) (length y)
2
ответ дан 6 December 2019 в 15:31
поделиться

ИМХО обычно UPXing не имеет смысла, но причины изложены выше, в основном, память дороже, чем диск.

Эрик: заглушка LZMA может быть больше. Даже если алгоритм лучше, он не всегда является чистым плюсом.

Менее двух десятых от одного процента строк исходного текста в компиляторе Glasgow Haskell упоминают «head», и, говоря о них, примерно половина находится в строковых литералах или комментариях. Это примерно одно использование 'head' на каждые 1500 строк кода.)

4
ответ дан 6 December 2019 в 15:31
поделиться

I'm on chapter 8, so I'm no old hand, but I'd prefer

areListsEqual x:xs y:ys = (x == y) && (areListsEqual xs ys)
areListsEqual [] [] = True
areListsEqual _ _ = False

It seems a bit more in line with Haskell style.

Similarly,

charlieSort [] = []
charlieSort (x:[]) = [x]
charlieSort (x1:x2:xs) = blah blah

swapPairIfNeed works as is because you only call it with first and second as its arguments (in that order), but you probably meant

swapPairIfNeed a b = if (length a >= length b)
    then [b, a]
    else [a, b]

In fact, I prefer the third case of charlieSort to look like

charlieSort (x1:x2:xs) = if not (areListsEqual x1:x2:xs wip)
                         then charlieSort wip
                         else wip
    where swapPairIfNeeded a b = if (length a >= length b)
                                 then (b, a)
                                 else (a, b)
          wip = f (swapPairIfNeeded first second)
          f (a, b) = a : (charlieSort b:xs)

I think this was all covered by chapter 3.

Now, let's examine the algorithm. Even holding ourselves to bubble sort, there's no need to check the whole list after sorting. Instead, we can swap the first two elements if necessary, then sort the tail of the list. If the head is shorter than the head of the sorted tail, we're done.

charlieSort (x1:x2:xs) = if (length a <= length (head sortedTail))
                         then a : sortedTail
                         else charlieSort (a : sortedTail)
    where sortedTail = charlieSort (b:xs)
          (a, b) = if (length x1 >= length x2)
                   then (x2, x1)
                   else (x1, x2)
1
ответ дан 6 December 2019 в 15:31
поделиться

Вы утверждаете, что сортировка по пузырькам - самый простой алгоритм сортировки, но здесь это не совсем так. Пузырьковая сортировка отлично подходит для массивов, где вы индексируете их линейно. Для связанных списков в Haskell сортировку вставкой на самом деле гораздо красивее.

Давайте начнем с функции insert :

winsert :: [a] -> [[a]] -> [[a]]
winsert x [] = [x]
winsert x (y:ys)
    | length x < length y = x : y : ys
    | otherwise = y : winsert x ys
  • Если список пуст, поместите в него x
  • Если список не пустой:
    • Если x , то x находится в начале списка
    • В противном случае, заголовок списка будет y , а Хвост состоит из x , вставляемых где-то в ys .

Далее, у нас есть фактическая функция сортировки:

wsort :: [[a]] -> [[a]]
wsort [] = []
wsort [x] = [x]
wsort (x:xs) = winsert x (wsort xs)
  • Если список пуст, вернуть его
  • Если список содержит только один элемент, его не нужно сортировать
  • . Если список длиннее этого, сортируйте xs , затем вставьте x в теперь отсортированный xs

Интересно, что путем изменения winsert для получения функции в качестве аргумента (вместо длины ), wsort можно использовать для сортировки на основе по всем видам критериев. Попробуйте создать список, который сортирует список списков на основе суммы каждого подсписка.

1
ответ дан 6 December 2019 в 15:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: