将Haskell(monadic)翻译为F#

问题描述:

帮我翻译下面的Haskell代码块。 运行函数产生对应于抽象为模式的给定正则表达式的文本字符串。 您可以在下面的F#代码块中看到类型Pattern的声明。您可以测试运行功能像将Haskell(monadic)翻译为F#

genex $ POr [PConcat [PEscape(DoPa 1) 'd'], PConcat [PEscape (DoPa 2) 'd']] 

{-# LANGUAGE RecordWildCards, NamedFieldPuns #-} 
import qualified Data.Text as T 
import qualified Control.Monad.Stream as Stream 
import Text.Regex.TDFA.Pattern 
import Control.Monad.State 
import Control.Applicative 

genex = Stream.toList . run 

maxRepeat :: Int 
maxRepeat = 3 

each = foldl1 (<|>) . map return 

run :: Pattern -> Stream.Stream T.Text 
run p = case p of 
    PBound low high p -> do 
     n <- each [low..maybe (low+maxRepeat) id high] 
     fmap T.concat . sequence $ replicate n (run p) 
    PConcat ps -> fmap T.concat . Stream.suspended . sequence $ map run ps 
    POr xs -> foldl1 mplus $ map run xs 
    PEscape {..} -> case getPatternChar of 
     'd' -> chars $ ['0'..'9'] 
     'w' -> chars $ ['0'..'9'] ++ '_' : ['a'..'z'] ++ ['A'..'Z'] 
     ch -> isChar ch 
    _  -> error $ show p 
    where 
    isChar = return . T.singleton 
    chars = each . map T.singleton 

下面我给我的可怜的尝试。它工作但不正确。问题在于以下。 让假设解析产生模式那样

解析 “\\ d \\ d” ;; val it:Pattern = POr [PConcat [PEscape(DoPa 1,'d'); PEscape(DOPA 2, 'd')]]

解析 “\\ d {2}” ;; VAL它:模式= POR [PConcat [PBound(2,某些2,PEscape(DOPA 1, 'd'))]]

所以供给两个图案到运行我希望收到SEQ [ [ '2'; '2']; [ '2'; '3']; [ '2'; '1']; [ '2'; '4']; ...],对应于seq [“22”; “23”; “21”; “24”; ...](2个每串符号)

这是在第一种情况下有效,

POR [PConcat [PEscape(DOPA 1, 'd'); PEscape(DoPa 2,'d')]] |>运行;; val it:seq = seq [['2'; '2']; [ '2'; '3']; [ '2'; '1']; [ '2'; '4']; ...]

seq [“22”; “23”; “21”; “24”; ...]

但不是在第二

POR [PConcat [PBound(2,一些2,PEscape(DOPA 1, 'd'))]] |>运行;; val it:seq = seq [['2']; [ '2']; [ '2']; [ '3']; ...]

seq [“2”; “2”,“2”; “3”,“2”; “1”,“2”; “4”; ...](每串1个符号)

我测试的不同的变体包含下列子句:

| POr ps    -> Seq.concat (List.map run ps) 
| PConcat ps   -> (sequence (List.map (run >> Seq.concat) ps)) 
| PBound (low,high,p) -> 

但一切都是徒劳。我无法弄清楚有效的翻译。

- 也许我应该使用字符串或数组而不是char列表。

-我认为Seq与Control.Monad相当好。流。这样对吗?

预先感谢帮助

open System 

/// Used to track elements of the pattern that accept characters or are anchors 
type DoPa = DoPa of int 

/// Pattern is the type returned by the regular expression parser. 
/// This is consumed by the CorePattern module and the tender leaves 
/// are nibbled by the TNFA module. 
type Pattern = PEmpty 
      | POr  of Pattern list     // flattened by starTrans 
      | PConcat of Pattern list     // flattened by starTrans 
      | PBound of int * (int option) * Pattern // eliminated by starTrans 
      | PEscape of DoPa * char     // Backslashed Character 

let maxRepeat = 3 

let maybe deflt f opt = 
    match opt with 
    | None -> deflt 
    | Some v -> f v 

/// Cartesian production 
/// try in F# interactive: sequence [[1;2];[3;4]];; 
let rec sequence = function 
    | []  -> Seq.singleton [] 
    | (l::ls) -> seq { for x in l do for xs in sequence ls do yield (x::xs) } 



let from'space'to'tilda  = [' '..'~'] |> List.ofSeq 
let numbers     = ['0'..'9'] |> List.ofSeq 
let numbers'and'alphas  = (['0'..'9'] @ '_' :: ['a'..'z'] @ ['A'..'Z']) |> List.ofSeq 
let whites     = ['\009'; '\010'; '\012'; '\013'; '\032' ] |> List.ofSeq 

let rec run (p:Pattern) : seq<char list> = 
    let chars chs = seq { yield [for s in chs -> s] } 
    match p with 
    | POr ps    -> Seq.concat (List.map run ps) 
    | PConcat ps   -> (sequence (List.map (run >> Seq.concat) ps)) 
    | PBound (low,high,p) -> 
     let ns = seq {low .. maybe (low + maxRepeat) id high} 
     Seq.concat (seq { for n in ns do yield sequence (List.replicate n (((run >> Seq.concat) p))) }) 
     // Seq.concat (seq { for n in ns do yield  ((List.replicate n (run p)) |> Seq.concat |> List.ofSeq |> sequence)}) 
     //((List.replicate low (run p)) |> Seq.concat |> List.ofSeq |> sequence) 
     // PConcat [ for n in ns -> p] |> run 
    | PEscape(_, ch) -> 
     match ch with 
     | 'd' -> chars numbers 
     | 'w' -> chars numbers'and'alphas 
     | ch -> chars [ch] 
    | _      -> Seq.empty 
+4

你没有一个简单的例子? - 至少删除不是星座的代码 – 2012-07-05 11:56:54

+0

@John Palmer:完成 – 2012-07-05 12:24:39

我不知道你为什么没有在F#从哈斯克尔翻译Data.Textstring,你只需要模仿两种功能。除此之外,我就是这样做了一些更改,使其工作,这样你可以用你原来的代码很容易进行比较,看之间(*。*)替换代码

open System 

// Mimic Data.Text as T 
module T = 
    let concat (x:seq<_>) = System.String.Concat x 
    let singleton (x:char) = string x 


/// Used to track elements of the pattern that accept characters or are anchors 
type DoPa = DoPa of int 

/// Pattern is the type returned by the regular expression parser. 
/// This is consumed by the CorePattern module and the tender leaves 
/// are nibbled by the TNFA module. 
type Pattern = PEmpty 
      | POr  of Pattern list     // flattened by starTrans 
      | PConcat of Pattern list     // flattened by starTrans 
      | PBound of int * (int option) * Pattern // eliminated by starTrans 
      | PEscape of DoPa * char     // Backslashed Character 

let maxRepeat = 3 

let maybe deflt f opt = 
    match opt with 
    | None -> deflt 
    | Some v -> f v 

/// Cartesian production 
/// try in F# interactive: sequence [[1;2];[3;4]];; 
let rec sequence = function 
    | []  -> Seq.singleton [] 
    | (l::ls) -> seq { for x in l do for xs in sequence ls do yield (x::xs) } 



let from'space'to'tilda  = [' '..'~'] |> List.ofSeq 
let numbers     = ['0'..'9'] |> List.ofSeq 
let numbers'and'alphas  = (['0'..'9'] @ '_' :: ['a'..'z'] @ ['A'..'Z']) |> List.ofSeq 
let whites     = ['\009'; '\010'; '\012'; '\013'; '\032' ] |> List.ofSeq 

let rec run (p:Pattern) (*: seq<char list> *) = 
    (* let chars chs = seq { yield [for s in chs -> s] } *) 
    let chars (chs:seq<char>) = Seq.map string chs 

    match p with 
    | POr ps    -> Seq.concat (List.map run ps) 
    | PConcat ps   -> Seq.map T.concat << sequence <| List.map run ps (* (sequence (List.map (run >> Seq.concat) ps)) *) 
    | PBound (low,high,p) -> 
     seq { 
     for n in [low..maybe (low+maxRepeat) id high] do 
      yield! ( (Seq.map T.concat << sequence) (List.replicate n (run p)))} 
     (*let ns = seq {low .. maybe (low + maxRepeat) id high} 
     Seq.concat (seq { for n in ns do yield sequence (List.replicate n (((run >> Seq.concat) p))) *) 

     // Seq.concat (seq { for n in ns do yield  ((List.replicate n (run p)) |> Seq.concat |> List.ofSeq |> sequence)}) 
     //((List.replicate low (run p)) |> Seq.concat |> List.ofSeq |> sequence) 
     // PConcat [ for n in ns -> p] |> run 
    | PEscape(_, ch) -> 
     match ch with 
     | 'd' -> chars numbers 
     | 'w' -> chars numbers'and'alphas 
     | ch -> chars [ch] 
    | _      -> Seq.empty 


UPDATE

如果您正在将Haskell代码翻译为F#,您可以尝试使用模仿许多Haskell函数的this code,包括使用类型类的那些函数。 我做了一个测试翻译尽可能接近你原来的Haskell代码,但使用F#列表(不要偷懒),看起来像这样:

#load "Prelude.fs" 
#load "Monad.fs" 
#load "Applicative.fs" 
#load "Monoid.fs" 

open Prelude 
open Control.Monad.Base 
open Control.Applicative 

module T = 
    let concat (x:list<_>) = System.String.Concat x 
    let singleton (x:char) = string x 

type DoPa = DoPa of int 

type Pattern = PEmpty 
      | POr  of Pattern list 
      | PConcat of Pattern list 
      | PBound of int * (int option) * Pattern 
      | PEscape of DoPa * char 

let maxRepeat = 3 

let inline each x = foldl1 (<|>) << map return' <| x 

let rec run p:list<_> = 
    let inline isChar x = return' << T.singleton <| x 
    let inline chars x = each << map T.singleton <| x 
    match p with 
    | PBound (low,high,p) -> do' { 
     let! n = each [low..maybe (low+maxRepeat) id high] 
     return! (fmap T.concat << sequence <| replicate n (run p))} 
    | PConcat ps -> fmap T.concat << sequence <| map run ps 
    | POr xs -> foldl1 mplus <| map run xs 
    | PEscape (_, ch) -> 
     match ch with 
     | 'd' -> chars <| ['0'..'9'] 
     | 'w' -> chars <| ['0'..'9'] @ '_' :: ['a'..'z'] @ ['A'..'Z'] 
     | ch -> isChar ch 
    | _ -> failwith <| string p 

let genex = run 
+0

非常感谢你的确非常好。你给了我线索。我会死在没有它在我的想法labirinth :) – 2012-07-06 04:11:08

+0

@ alexander.vladislav.popov如果你是从Haskell到F#的代码翻译,请参阅更新。 – Gustavo 2012-07-07 10:24:12

+0

请原谅你遗漏的答案。非常有用。 – 2012-07-13 03:27:40