C ++ для функциональных - PullRequest
1 голос
/ 14 февраля 2009

Мне интересно, как это сделать на функциональном языке программирования. Может быть, F # или Haskell.

Может кто-нибудь показать мне пример без использования каких-либо вызовов функций, кроме find и rfind?

Эта функция находит следующую косую черту, используя i в качестве числа slash (<0 для обратного направления). </p>

size_t findSlash(const char *sz, size_t i)
{
    std::string s = sz;
    size_t a, b, c, n, ai = abs(i), pos=0;
    for (n=0; n<ai; n++)
    {
        if (i<0)
        {
            a = s.rfind("\\", pos);
            b = s.rfind("/", pos);
        }
        else
        {
            a = s.find("\\", pos);
            b = s.find("/", pos);
        }
        if (a==-1u)
        {
            if (b==-1u)
                return pos;
            c = b;
        }
        else if (b==-1u)
            c = a;
        else
            c = min(a, b);
        pos = c+1;
    }
    return c;
}

Ответы [ 4 ]

13 голосов
/ 14 февраля 2009

Haskell:

import Data.List

findSlash :: String -> Int -> Int
findSlash str i = findIndices (\c -> c == '\\' || c == '/') str !! i

Обработка отрицательного индекса (что некрасиво, потому что вы действительно не хотите этого делать):

findSlash :: String -> Int -> Int
findSlash str i =
    index (findIndices (\c -> c == '\\' || c == '/') str) i
          where index xs i | i  < 0 = (reverse xs) !! ((-i) - 1)
                           | i >= 0 = xs !! i

Обработка ошибок:

findSlash :: String -> Int -> Maybe Int
findSlash str i = index i
    where xs = findIndices (\c -> c == '\\' || c == '/') str
          l = length xs
          index i
              | i <  0 && i < (-l) = Nothing
              | i >= 0 && i >= l   = Nothing
              | i <  0             = Just $ (reverse xs) !! ((-i) - 1)
              | i >= 0             = Just $ xs !! i

Теперь вы можете сказать:

map (findSlash "/foo/bar/baz") [-4..4]

и получите:

-- -4        -3     -2     -1      0      1      2       3       4
[Nothing,Just 0,Just 4,Just 8,Just 0,Just 4,Just 8,Nothing,Nothing]

В любом случае, обработка смещения от конца делает код довольно уродливым и лишает возможности ленивых вычислений. Поэтому я думаю, что большинство людей будет использовать первый, возможно, с небольшой проверкой ошибок. (Это также убивает лень, поскольку длина вызовет оценку всего списка. Вы можете использовать «drop» вместо «!!» однако, чтобы избежать ошибок и предотвратить оценку всего списка результатов. TMTOWTDI.)

7 голосов
/ 14 февраля 2009

Во-первых, ваш код не работает. size_t является типом без знака и никогда не может быть i<0.

Во-вторых, ваш код - это уродливое использование библиотеки std и неэффективное. Там должна быть библиотека регулярных выражений или тому подобное или использовать ручной сканер. Результирующий код намного чище и быстрее. Например (я не использую C много лет, но приведенный ниже код, созданный за 10 минут, работает.):

size_t findSlash(const char *sz, int i)
{
    const char *s = sz;
    if (i<0) {
        for(;*s;s++);
        for(;;s--){
            if(s<sz) return -1;
            if((*s == '/') || (*s == '\\'))
                if(! ++i) break;
        }
    }
    else {
        for(;;s++){
            if(! *s) return -1;
            if((*s == '/') || (*s == '\\'))
                if(! i--) break;
        }
    }
    return s-sz;
}

Я не писал на Haskell или F #, но, например, код ниже на Erlang должен указывать, как это сделать на функциональном языке:

findslash(L, I) when is_list(L), is_integer(I) ->
    if  I<0  ->
            case findslash(lists:reverse(L), -1*I - 1, 0) of
                none -> none;
                X -> length(L) - X - 1
            end;
        I>=0  -> findslash(L, I, 0)
    end.

findslash([H|_], 0, X) when H=:=$/; H=:=$\\ -> X;
findslash([H|T], I, X) when H=:=$/; H=:=$\\ ->
    findslash(T, I-1, X+1);
findslash([_|T], I, X) -> findslash(T, I, X+1);
findslash([], _, _) -> none.

Моя попытка в Haskell с проверкой ошибок и ленью для i> = 0:

findSlash :: String -> Int -> Maybe Int
findSlash str i
  | i <  0 = reversed (_findSlash (reverse str) (-1*i-1) 0)
  | i >= 0 = _findSlash str i 0
    where
      reversed Nothing  = Nothing
      reversed (Just a) = Just ((length str) - a - 1)
      _findSlash (x:xs) i n
        | x == '/' || x == '\\' = if i==0 then Just n else _findSlash xs (i-1) (n+1)
        | True                  =                          _findSlash xs  i    (n+1)
      _findSlash []     _ _     = Nothing
4 голосов
/ 15 февраля 2009

Вы можете написать чисто функциональный код на чистом C:

/** Return pointer to the `n`-th occurrence of any char from `chars` in `s`.

    Return NULL if it can't find the `n`-th occurrence.  
    Start at the end of `s` if `n` is negative.
    `n` is zero-based.
*/
const char* 
find_nth(const char* s, int n, const char* chars) 
{
  if (n < 0) return rfind_nth(s, -(n+1), chars);
  if (! (s && *s)) return NULL;
  if (find(chars, *s)) return (n == 0) ? s : find_nth(s+1, n-1, chars);
  else return find_nth(s+1, n, chars);
}

Полная программа:

#include <string.h>

const char* 
find(const char* s, char c) 
{
  if (! (s && *s)) return NULL;
  return (*s == c) ? s : find(s + 1, c);
}

const char* 
rfind_nth_range(const char* s, const char* end, size_t n, const char* chars)
{
  if (! (s && end && (end - s) > 0)) return NULL;
  if (find(chars, *(end - 1))) // `*(end-1)` is in `chars`
    return (n == 0) ? end - 1 : rfind_nth_range(s, end - 1, n-1, chars);
  else
    return rfind_nth_range(s, end - 1, n, chars);
}

const char* 
rfind_nth(const char* s, size_t n, const char* chars)
{
  return rfind_nth_range(s, s + strlen(s), n, chars);
}

int 
main(void) 
{
  const char* const s = "ab/cd\\e";
  return !(find_nth(s, 1, "/\\") == (s+5));
}
3 голосов
/ 14 февраля 2009

Итак, что это? Находит ли он только i-й слеш (вперед или назад) в строке (или «-i» с конца, если i отрицателен)? Я не уверен, правильно ли я это понял, просто прочитав код.

В любом случае, это было бы просто для порта, но не ясно, какова ваша цель / цель.

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