[英]translate Haskell (monadic) to F#
Help me translate following block of the Haskell code. 帮我翻译以下Haskell代码块。 The run function produces text string that corresponding to a given regex that abstracted as Pattern.
run函数产生文本字符串,该字符串对应于抽象为Pattern的给定正则表达式。 Declaration of the type Pattern you can see below in the block of F# code.
您可以在下面的F#代码块中看到Pattern类型的声明。 You can test run function like
您可以测试运行功能,例如
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
Below I give my poor attempt. 下面,我尝试一下。 It works but incorrectly.
它有效,但不正确。 The problem is in the following.
问题出在下面。 Let assume parse produces Pattern like that
假设解析产生这样的Pattern
parse "\\\\d\\\\d";;
解析“ \\\\ d \\\\ d” ;; val it : Pattern = POr [PConcat [PEscape (DoPa 1,'d');
值:模式= POr [PConcat [PEscape(DoPa 1,'d'); PEscape (DoPa 2,'d')]]
PEscape(DoPa 2,'d')]]
and 和
parse "\\\\d{2}";;
解析“ \\\\ d {2}” ;; val it : Pattern = POr [PConcat [PBound (2,Some 2,PEscape (DoPa 1,'d'))]]
值:模式= POr [PConcat [PBound(2,Some 2,PEscape(DoPa 1,'d'))]]
So feeding both patterns to run I expect to receive seq [['2'; 因此,这两种模式都可以运行,我希望收到seq [['2'; '2'];
'2']; ['2';
[ '2'; '3'];
'3']; ['2';
[ '2'; '1'];
'1']; ['2';
[ '2'; '4'];
'4']; ...] that corresponding to seq ["22";
...]对应于seq [“ 22”; "23";
“23”; "21";
“21”; "24";
“24”; ...] (2 symbols per string)
...] (每个字符串2个符号)
This is valid in the first case, 这在第一种情况下有效,
POr [PConcat [PEscape (DoPa 1,'d');
POr [PConcat [PEscape(DoPa 1,'d'); PEscape (DoPa 2,'d')]] |> run;;
PEscape(DoPa 2,'d')]] |>运行;; val it : seq = seq [['2';
val it:seq = seq [['2'; '2'];
'2']; ['2';
[ '2'; '3'];
'3']; ['2';
[ '2'; '1'];
'1']; ['2';
[ '2'; '4'];
'4']; ...]
...]
seq ["22"; seq [“ 22”; "23";
“23”; "21";
“21”; "24";
“24”; ...]
...]
but not in the second 但不是第二
POr [PConcat [PBound (2,Some 2,PEscape (DoPa 1,'d'))]] |> run;;
POr [PConcat [PBound(2,Some 2,PEscape(DoPa 1,'d'))]] |>运行;; val it : seq = seq [['2'];
val it:seq = seq [['2']; ['2'];
[ '2']; ['2'];
[ '2']; ['3'];
[ '3']; ...]
...]
seq ["2"; seq [“ 2”; "2", "2";
“ 2”,“ 2”; "3", "2";
“ 3”,“ 2”; "1", "2";
“ 1”,“ 2”; "4";...] (1 symbol per string)
“ 4”; ...] (每个字符串1个符号)
I tested different variants with the following clauses: 我使用以下条款测试了不同的变体:
| POr ps -> Seq.concat (List.map run ps)
| PConcat ps -> (sequence (List.map (run >> Seq.concat) ps))
| PBound (low,high,p) ->
but all in vain. 但都是徒劳的。 I can't figure out the valid translation.
我不知道有效的翻译。
-Maybe I should use String or Array instead of char list. -也许我应该使用String或Array而不是char列表。
-And I assume that Seq is quite good analogue to Control.Monad.Stream. -我认为Seq非常类似于Control.Monad.Stream。 Is it right?
这样对吗?
Thanks in advance for help 预先感谢您的帮助
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
I don't know why you didn't translate Data.Text
from Haskell to string
in F#, you just need to mimic two functions. 我不知道为什么不将Haskell的
Data.Text
转换为F#中的string
,您只需要模仿两个函数即可。 Apart from that I did just a few changes to make it work, this way you can compare it easily with your original code, see replaced code between (* *) 除此之外,我仅作了一些更改以使其工作,这样您就可以轻松地将其与原始代码进行比较,请参阅(* *)之间的替换代码
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 UPDATE
If you are translating Haskell code to F# you may try using this code which mimics many Haskell functions, including those using Type Classes. 如果要将Haskell代码转换为F#,则可以尝试使用模仿许多Haskell函数(包括使用类型类的那些函数)的代码 。 I did a test translating as close as possible to your original Haskell code but using F# List (not lazy) and looks like this:
我做了一个尽可能接近原始Haskell代码的测试,但是使用F#List(不是惰性的),它看起来像这样:
#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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.