๐Ÿ”™ Back to Top

Sun Jun 26 21:16:15 JST 2016

ๅ‚่€ƒ

Rust ใงใƒ‘ใƒผใ‚ถใ‚ณใƒณใƒ“ใƒใƒผใ‚ฟใ‚’ๆ›ธใ

ๅž‹

ๆ‰ฑใ„ใ‚„ใ™ใ•ใฎใŸใ‚ใซใ€ๅ…ฅๅŠ›ใจใชใ‚‹ๆ–‡ๅญ—ๅˆ—ใ‚’ๅ…จใฆ Vec<char> ใจไปฎๅฎšใ™ใ‚‹.
ใƒ‘ใƒผใ‚ถใฏใ€ Vec<char> ใ‚’ๅ…ฅๅŠ›ใจใ—ใฆๅ—ใ‘ๅ–ใ‚Šใ€ๆถˆ่ฒปใ—ใŸ (่ชญใ‚“ใ ) ๅˆ†ใจใ€ใพใ ่ชญใ‚“ใงใชใ„ๅˆ†ใฎใƒšใ‚ข (Vec<char>, Vec<char>) ใ‚’่ฟ”ใ™้–ขๆ•ฐใงใ‚ใ‚‹.
ใŸใ ใ—ใ€ใƒ‘ใƒผใ‚นใฏๅธธใซๆˆๅŠŸใ™ใ‚‹ใจใฏ้™ใ‚‰ใชใ„ใฎใงใ€ใใ‚Œใ‚’ๆ›ดใซ Option ใงๅŒ…ใ‚€. ใ“ใฎ่ฟ”ใ™ๅž‹ใ‚’ ParseResult ใจใ™ใ‚‹.
ใ—ใŸใŒใฃใฆใ€ใƒ‘ใƒผใ‚ถใฏ Vec<char> ใ‚’ๅ–ใฃใฆ ParseResult ใ‚’่ฟ”ใ™้–ขๆ•ฐใงใ‚ใ‚‹ใŒใ€้ƒฝๅˆไธŠใ€ใใ‚Œใ‚’ Box ใซๅŒ…ใ‚“ใงใ—ใ‹ใ‚‚ Parser ใจๅไป˜ใ‘ใŸ struct ใงๅŒ…ใ‚€.

type ParseResult = Option<(Vec<char>, Vec<char>)>;
struct Parser(Box<Fn(&Vec<char>) -> ParseResult>);

้–ขๆ•ฐๅž‹ใฃใฝใๆ›ธใๅ ดๅˆใฏใ€ๅ…ฅๅŠ›ใฏๅ‚็…ง & ไป˜ใ‘ใฆ่ชญใ‚ใฐๅคงไฝ“ใ„ใ„ๆฐ—ใŒใ™ใ‚‹.

ๅŸบๆœฌใƒ‘ใƒผใ‚ถ

ๅ‚่€ƒใ‚นใƒฉใ‚คใƒ‰ใซใ—ใŸใŒใฃใฆใ€1ๆ–‡ๅญ—ใ ใ‘ใ‚’่ชญใ‚€ใƒ‘ใƒผใ‚ถ (one_of) ใจ้ ญใฎไฝ•ๆ–‡ๅญ—ๅŒ–ใ‚’่ชญใ‚€ใƒ‘ใƒผใ‚ถ (string) ใ‚’ๅฎŸ่ฃ…ใ™ใ‚‹.

one_of

้ ญใฎไธ€ๆ–‡ๅญ—ใ‚’ไธŽใˆใฆใ€ๆถˆ่ฒปใ•ใ›ใ‚‹ใƒ‘ใƒผใ‚ถใ‚’ไฝœใ‚‹.

fn one_of(c: char) -> Parser {
    Parser(Box::new(move |cs: &Vec<char>| {
        if cs.len() == 0 || cs[0] != c {
            None
        } else {
            Some((vec![c], cs[1..].to_owned()))
        }
    }))
}

ๆ–‡ๅญ— c ใ‚’ๅ—ใ‘ๅ–ใฃใฆๆฌกใฎใ‚ˆใ†ใชใƒ‘ใƒผใ‚ถ (Parser) ใ‚’่ฟ”ใ™. ใƒ‘ใƒผใ‚ถใฏๆ–‡ๅญ—ๅˆ— cs ใ‚’ๅ—ใ‘ๅ–ใฃใฆใ€้ ญใฎไธ€ๆ–‡ๅญ—ใŒ c ใจไธ€่‡ดใ—ใŸใ‚‰ใ€ใใ‚Œใ‚’ๆถˆ่ฒปใ—ใฆใ€ๆฎ‹ใ‚Š (cs[1..]) ใ‚’ๆถˆ่ฒปใ›ใšใซ่ฟ”ใ™. ้ ญใŒไธ€่‡ดใ—ใชใ„ใ‹ใ€ใใ‚‚ใใ‚‚ cs ใŒ้•ทใ•0ใฎๅ ดๅˆใฏ้ ญใŒ็„กใ„ใฎใงๅคฑๆ•— None ใ‚’่ฟ”ใ™.

ใƒ‘ใƒผใ‚ถใฎ้ฉ็”จ

ไฝœใฃใŸใƒ‘ใƒผใ‚ถใŒๆญฃใ—ใๅ‹•ไฝœใ™ใ‚‹ใ‹ใ‚’็ขบ่ชใ—ใŸใ„ใฎใงใ€ๅ…ˆใซใ€ใƒ‘ใƒผใ‚ถใ‚’ๆ–‡ๅญ—ๅˆ—ใซ้ฉ็”จใ™ใ‚‹ใƒกใ‚ฝใƒƒใƒ‰ใ‚’ๅฎŸ่ฃ…ใ™ใ‚‹.

impl Parser {
    fn call(&self, s: String) -> ParseResult {
        let Parser(ref f) = *self;
        let chars = s.chars().collect::<Vec<_>>();
        f(&chars)
    }
}

ใƒ‘ใƒผใ‚ถ (self) ใฎไธญ่บซใ‚’ let Parser(ref f) = ... ใฎ้ƒจๅˆ†ใง f ใจใ„ใ†ๅๅ‰ใ‚’ไป˜ใ‘ใฆๅ–ใ‚Šๅ‡บใ™. BoxใซๅŒ…ใ‚“ใงใ‚‹ใŒใ€ใใฎใพใพ้–ขๆ•ฐใจใ—ใฆไฝฟใˆใฐ่‰ฏใ„. ใ‚ใ–ใ‚ใ– ref ใง้–ขๆ•ฐใ‚’ๅ‚็…งใ—ใฆใ‚‹ใฎใฏใ€parser ใ‚’็นฐใ‚Š่ฟ”ใ—ไฝ•ๅบฆใ‚‚ๅˆฉ็”จใ™ใ‚‹ใŸใ‚ (ๅ€Ÿ็”จใฎใ‚ขใƒฌ).

ไพ‹

ๅ…ˆใปใฉใฎ one_of ใ‚’ไฝฟใฃใฆใฟใ‚‹.

    let parser = one_of('a');
    let s = String::from("abc");
    println!("{:?}", parser.call(s));

=>

Some((['a'], ['b', 'c']))

string

fn string(s: String) -> Parser {
    let ds: Vec<char> = s.chars().collect();
    Parser(Box::new(move |cs: &Vec<char>| {
        let n = ds.len();
        if cs.len() < n { return None }
        for i in 0..n {
            if ds[i] != cs[i] { return None }
        }
        Some((ds.to_owned(), cs[n..].to_owned()))
    }))
}

ๅŸบๆœฌ็š„ใซ one_of ใจๅŒใ˜.

ๅˆๆˆใ‚ณใƒณใƒ“ใƒใƒผใ‚ฟ

้ธๆŠž choose /

2ใคใฎใƒ‘ใƒผใ‚ถใ‚’ไธŽใˆใฆใ€1ใคใ‚ใ‚’่ฉฆใ—ใฆๆˆๅŠŸใ—ใŸใ‚‰ใใ‚Œใ‚’่ฟ”ใ™. ๅคฑๆ•—ใ—ใŸใ‚‰2ใค็›ฎใ‚’่ฟ”ใ™ใ€ใจใ„ใ†ใƒ‘ใƒผใ‚ถใ‚’็”Ÿๆˆใ™ใ‚‹ใ‚ณใƒณใƒ“ใƒใƒผใ‚ฟใ‚’ๅฎŸ่ฃ…ใ™ใ‚‹.

ๅ…ˆใซไฝฟใ„ๆ–นใ‚’่ฟฐในใ‚‹ใจ

    let parser = one_of('a') / one_of('b'); // 'a' ใ‚’่ชญใ‚€. ๅคฑๆ•—ใ—ใŸใ‚‰ใ€'b' ใ‚’่ชญใ‚€
    {
        let s = String::from("abc");
        println!("{:?}", parser.call(s));
    }
    {
        let s = String::from("bbc");
        println!("{:?}", parser.call(s));
    }
    {
        let s = String::from("cbc"); // fails
        println!("{:?}", parser.call(s));
    }

็ตๆžœใฏ้ †ใซ

Some((['a'], ['b', 'c']))
Some((['b'], ['b', 'c']))
None

้ฉ็”จใ™ใ‚‹้–ขๆ•ฐใ‚’ๅ…ˆใซ่ฟฐในใŸใฎใงใ€ใใ‚Œใ‚’ไฝฟใˆใฐใ„ใ„ใ ใ‘. 1ใคใ‚ใ‚’้ฉ็”จใ—ใฆใ€ None ใ‚’่ฟ”ใ—ใŸใ‚‰2ใคใ‚ใฎ้ฉ็”จใ—ใŸ็ตๆžœใ‚’่ฟ”ใ™. choose ใจใ„ใ†ๅๅ‰ใฎ้–ขๆ•ฐใจใ—ใฆๅฎŸ่ฃ…ใ™ใ‚‹.

fn choice(p1: Parser, p2: Parser) -> Parser {
    let Parser(f1) = p1;
    let Parser(f2) = p2;
    Parser(Box::new(move |cs: &Vec<char>| {
        if let Some(a) = f1(&cs) {
            Some(a)
        } else {
            f2(&cs)
        }
    }))
}

ใกใ‚‡ใฃใจ่ฉฐใพใ‚Šใƒใ‚คใƒณใƒˆใจใ—ใฆใฏใ€f1(cs) ใง cs ใŒใ‚ใฃใกใซ่กŒใฃใกใ‚ƒใฃใฆไฝฟใˆใชใใชใ‚‹ใฎใง clone ใ‚’ๆธกใ™. ใฆใ‹ๆ™ฎ้€šใซใ€ๅ…ฅๅŠ›ใ‚’ๅ‚็…งใงๅ—ใ‘ๅ–ใ‚‹ใ‚ˆใ†ใซใƒ‘ใƒผใ‚ถใ‚’ๅฎš็พฉใ™ใ‚Œใฐใ‚ˆใ‹ใฃใŸใชใ. ไปŠๆ›ดใ„ใฃใ‹.

ๆผ”็ฎ—ๅญ / ใงๆ›ธใ‘ใŸใปใ†ใŒใกใ‚‡ใฃใจใ‹ใฃใ“ใ„ใ„ใฎใงใ€ๆผ”็ฎ—ๅญใ‚ชใƒผใƒใƒผใƒญใƒผใƒ‰ใ™ใ‚‹.

use std::ops::Div;
impl Div for Parser {
    type Output = Parser;
    fn div(self, rhs: Parser) -> Parser { choice(self, rhs) }
}

้€ฃๆŽฅ then +

ไปŠๅบฆใฏใ€2ใคใฎใƒ‘ใƒผใ‚ถใ‚’้ †ใซ้ฉ็”จใ™ใ‚‹ใจใ„ใ†ใƒ‘ใƒผใ‚ถใ‚’็”Ÿๆˆใ™ใ‚‹. ใฉใฃใกใ‹ใงใƒ‘ใƒผใ‚นใซๅคฑๆ•—ใ™ใ‚Œใฐใ€ๅ…จไฝ“ใจใ—ใฆใ‚‚ๅคฑๆ•—ใจใ™ใ‚‹.

choose ใ‚’ใกใ‚‡ใฃใจๆ›ธใ็›ดใ™ใ ใ‘ใงใ„ใ„.

fn then(p1: Parser, p2: Parser) -> Parser {
    let Parser(f1) = p1;
    let Parser(f2) = p2;
    Parser(Box::new(move |cs: &Vec<char>| {
        if let Some((xs, ys)) = f1(&cs) {
            if let Some((xs2, ys2)) = f2(&ys) {
                let mut mxs = xs.clone();
                let mut mxs2 = xs2.clone();
                mxs.append(&mut mxs2);
                return Some((mxs.to_owned(), ys2))
            }
        }
        None
    }))
}

use std::ops::Add;
impl Add for Parser {
    type Output = Parser;
    fn add(self, rhs: Parser) -> Parser { then(self, rhs) }
}

ไพ‹

    let parser = (string(String::from("A")) / string(String::from("The"))) + one_of(' ') + string(String::from("cat"));
    {
        let s = String::from("My cat"); // fails
        println!("{:?}", parser.call(s));
    }
    {
        let s = String::from("The cat");
        println!("{:?}", parser.call(s));
    }
}
None
Some((['T', 'h', 'e', ' ', 'c', 'a', 't'], []))

ใฆใ„ใ†ใ‹ๆฏŽๅ›ž String::from ใคใ‘ใ‚‹ใฎใ ใ‚‹ใ„.

src