带记忆的elm中最长公共子序列

带记忆的elm中最长公共子序列,elm,memoization,lcs,Elm,Memoization,Lcs,我想在elm中制作一个LCS算法的高效版本。 我喜欢这个ocaml版本,但它使用副作用来缓存结果 let lcs xs ys = let cache = Hashtbl.create 16 in let rec lcs xs ys = try Hashtbl.find cache (xs, ys) with | Not_found -> let result = match xs, ys with | [],

我想在elm中制作一个LCS算法的高效版本。 我喜欢这个ocaml版本,但它使用副作用来缓存结果

let lcs xs ys =
  let cache = Hashtbl.create 16 in
  let rec lcs xs ys =
    try Hashtbl.find cache (xs, ys) with
    | Not_found ->
        let result =
          match xs, ys with
          | [], _ -> []
          | _, [] -> []
          | x :: xs, y :: ys when x = y ->
              x :: lcs xs ys
          | _ :: xs_rest, _ :: ys_rest ->
              let a = lcs xs_rest ys in
              let b = lcs xs      ys_rest in
              if (List.length a) > (List.length b) then a else b
        in
        Hashtbl.add cache (xs, ys) result;
        result
  in
  lcs xs ys

如果我想在elm中使用回忆录,我应该怎么做?

您可能需要研究使用,它执行自动回忆录,或者使用,它使用显式回忆录

通过在
Lazy
中包装内部递归函数,可以减少求值次数。在我的示例中,惰性版本大约有300个
Debug
日志条目,非惰性版本大约有700个条目。

Gilbert Kennen给了我一个似乎工作得更好的版本:

lcs : List a -> List a -> List a
lcs xs ys =
    lcsHelper xs ys ( 0, 0 ) Dict.empty
        |> Dict.get ( 0, 0 )
        |> Maybe.map Tuple.second
        |> Maybe.withDefault []


lcsHelper : List a -> List a -> ( Int, Int ) -> Dict ( Int, Int ) ( Int, List a ) -> Dict ( Int, Int ) ( Int, List a )
lcsHelper xs ys position memo =
    case ( Dict.get position memo, xs, ys ) of
        ( Nothing, x :: xRest, y :: yRest ) ->
            let
                nextYPos =
                    Tuple.mapSecond ((+) 1) position

                nextXPos =
                    Tuple.mapFirst ((+) 1) position

                newMemo =
                    memo
                        |> lcsHelper xs yRest nextYPos
                        |> lcsHelper xRest ys nextXPos

                best =
                    maxListTuple
                        (get nextXPos newMemo)
                        (get nextYPos newMemo)
                        |> consIfEqual x y
            in
                Dict.insert position best newMemo

        _ ->
            memo

get : ( Int, Int ) -> Dict ( Int, Int ) ( Int, List a ) -> ( Int, List a )
get position memo =
    Dict.get position memo |> Maybe.withDefault ( 0, [] )


maxListTuple : ( Int, List a ) -> ( Int, List a ) -> ( Int, List a )
maxListTuple ( xLen, xs ) ( yLen, ys ) =
    if yLen > xLen then
        ( yLen, ys )
    else
        ( xLen, xs )


consIfEqual : a -> a -> ( Int, List a ) -> ( Int, List a )
consIfEqual x y ( listLen, list ) =
    if x == y then
        ( listLen + 1, x :: list )
    else
        ( listLen, list )

它使用一个字典来缓存结果。

即使有惰性,我仍然不知道如何在递归调用的不同分支之间传递值。