式評価および木徒歩多型を用い?(ala Steve Yegge)
-
08-06-2019 - |
質問
今朝、私は読み Steve Yegge:時多型に失敗した, いった質問をツイッターの使用をお願い可能性従業員のうためには、面接時にAmazon.
例として、多 行動に見られるように、クラシック "エバール"面接質問する(て かってもたらされたアマゾン によるロンBraunstein.問題は 非常に豊かなどで管理する プローブなど スキル:OOPデザイン、繰返し、バイナリ 樹木の多型およびランタイム タイピング,一般符号化技術、および(場合 したいでく) 構文解析理論。
ある時点の候補者が期待 を実現することでも表現できる 算術演算の表現としてのバイナリー ツリーを想定し、ご利用いただける利用 バイナリー事業者などの"+","-", "*","/".葉ノードをすべて 番号、内部ノード すべてのオペレータ.を評価する 表現手段を歩きます。の場合 の候補としないこ きくいった場合や、 必要なだけお伝えします。
場合でも伝えできるようになり、 興味深い問題です。
前半の問題、 人(名ま の保護のために私は、死の息吹が、その イニシャルウィリールイス)が感じ取れる ジョブ要求したい場合は呼び出 自分で開発で働いている Amazon、実際にちょっとつらいです。の 質問はだから 算術演算の表現(例えばa 文字列)"など2+(2)"へ 表現。があるかもしれませんADJ チャレンジで、この問いに対する一 ポイント。
後半には:ということかこ 2人プロジェクト、パートナー いだし、通話"ウィリー"、 に変えるの 文字列表現。す のですが、やはり:必要なものかを決める 授業はWillieの構築 ツリーます。の取得ができないことがありいず 言語を確認してくださいだり、 またはウィリーまでの手で組み立て 言語です。その気持ちorneryで するためのプロセッサとは 長い製造される。
まっきっと驚かれるなど多くの候補者 boffます。
んですが、それぞれの答えが 標準悪液の使用 のスイッチやケースstatment(ただ 良き昔ながらのカスケード型-ifs).A 少し、よりよい解決方法を テーブルを使用しての機能へのポインタ のょう液 有用である多型.I になることをおすすめ作品を通して を受けます。楽しいチャンスが得られます。
うようになったので、問題に対処するためのすべてを生成します。だから演算の表現(例えば文字列)"など2+(2)"を表すツリーをカスケード型の場合、テーブルの機能のポインタ、および/または多型?
お気軽に取り組む、または全です。
[更新タイトル変更により良い試合のほとんどが回答しております。]
解決
多様な樹木を歩く, Python版
#!/usr/bin/python
class Node:
"""base class, you should not process one of these"""
def process(self):
raise('you should not be processing a node')
class BinaryNode(Node):
"""base class for binary nodes"""
def __init__(self, _left, _right):
self.left = _left
self.right = _right
def process(self):
raise('you should not be processing a binarynode')
class Plus(BinaryNode):
def process(self):
return self.left.process() + self.right.process()
class Minus(BinaryNode):
def process(self):
return self.left.process() - self.right.process()
class Mul(BinaryNode):
def process(self):
return self.left.process() * self.right.process()
class Div(BinaryNode):
def process(self):
return self.left.process() / self.right.process()
class Num(Node):
def __init__(self, _value):
self.value = _value
def process(self):
return self.value
def demo(n):
print n.process()
demo(Num(2)) # 2
demo(Plus(Num(2),Num(5))) # 2 + 3
demo(Plus(Mul(Num(2),Num(3)),Div(Num(10),Num(5)))) # (2 * 3) + (10 / 2)
この試験はビルをバイナリの木を使用のコンストラクタ.
プログラム構造:
抽象基底クラス:ノード
- すべてのノードがこのクラスを継承
抽象基底クラス:BinaryNode
- すべてのバイナリー事業者にこのクラスを継承
- セメソッドは、仕事のevalutingの発現および結果の返却
バイナリーオペレータークラスプラス、マイナスの状況の中、Mul部門
- 二子ノードがそれぞれの左側と右側subexpressions
番号クラス:Num
- 開催葉ノードでは、数値など17 42
他のヒント
の問題だと思いる必要がありますperenthesesとが見つけられない存在になっているバイナリーオペレーター?すべてのもの(2)として単一のトークンを評価する2?
のパーなホームページからシンプルに表現のツリーが、ついに影響を及ぼします。E.g.) ツリーのために(1+2)+3から1+(2+3):
+
/ \
+ 3
/ \
1 2
対
+
/ \
1 +
/ \
2 3
の括弧内の"ヒント"のパーザ(例えば、superjoe30、"再帰的に降")
を表すノード
していくために、どのようななどの括弧、5種類のノードをぶら下げるフィールド
のバイナリーノードをぶら下げるフィールド追加マイナスMul Div
これら二つの子供の左右側+ / \ node node
ノードに値:Val
子ノード、数値ノードのパー:Paren
単一の子ノードのsubexpression( ) | node
ために結晶の溶液に、そしてこのようなクラスの関係:
- ノード
- BinaryNode:からの継承ノード
- プラス:継承からのバイナリーノード
- マイナス:継承からのバイナリーノード
- Mul:継承からのバイナリーノード
- Div:継承からのバイナリーノード
- 値:からの継承ノード
- Paren:からの継承ノード
ある仮想関数がすべてのノードと呼ばれeval().お問い合わせいただいた場合の機能での値を返すことsubexpression.
文字列トークナイザ+LL(1)のパーサで表すツリーまで---の多型方を抽象的な演算のクラスと評価(a,b)"機能は、オーバーライドそれぞれの事業者の関係は、加算、減算など)を返すには適切な値のツリーを含む整数の算術演算子を評価することができるか-注文フォーカストラバーサルします。
んですが、それぞれの答えが 標準悪液の使用 のスイッチやケースstatment(ただ 良き昔ながらのカスケード型-ifs).A 少し、よりよい解決方法を テーブルを使用しての機能へのポインタ のょう液 有用である多型.
最後の二十数年の進化の通訳者として見ることができ、他方の多型(例えば、ナイーブSmalltalk metacircular通訳者)の関数ポインタ(素朴lispの実装,レコード、C++)をスイッチ(ナイーブのバイトコード通訳)、それ以降JITsいるいずれかを必要と非常に大きなクラス、または(独多様な言語)をダブル派遣を低減する多型をタイプの場合、通りにありますのでステージです。う定義の"最善"を使用。
簡単なも多形解OK- ここでの私の作前, が、いずれかのスタックとbytecode/スイッチを利用し、ランタイムのコンパイラが通常より良いれば、描画機能により、数千のデータポイント。
Hm...しないほうがいいと思いますトップダウンのための連想パーザaspことなく後退では何らかのシフト削減のパーサです。LR(1)なLALRの仕事は、イブレア城、イブレア以下の(アドホック)言語の定義:
スタート->E1
E1->E1+E1|E1-E1
E1->E2*E2|E2/E2|E2
E2-> 番号 |(E1)
分離でE1およびE2に必要なものは、優先順位*や/上+と-.
この場合どのような場合があったので書き、パーサにより手:
- 二書庫は、保存のノードツリーのオペランドとしてと保存事業者
- 読みを入力左右には、葉ノードの番号を押して、オペランドスタックです。
- ま>=2オペランドのスタック、ポップ2を組み合わせることで、いの一番上のオペレーターのオペレーターのスタックを押し構造体のオペランドがツリー ない限り
- 次のオペレーターの高い優先順位の一つで、現在のスタックです。
この問題の取り扱いていただけるボディーです。一雅(i)の溶液は、優先の各オペレーターとしての番号に変更します。なので最初は、
- intプラス、マイナス=1;
- int mul,div=2;
現在まで残ブラケット増分値は全てこれらの変数により2時まで右ブラケット、減分すべての変数による2.
そうすることに+3*(4+5)高い優先順位の*3*4な押し出された、スタックです。代わりにまで5、4+5、プ3*(4+5).
Re:ジャスティン
私のツリーが見て思ったこと。
+
/ \
2 ( )
|
2
基本的にはあるんで"エバール"のノードでの評価、木下します。して最適化することだけれ
+
/ \
2 2
この場合、パーなのに必要な追加ものです。なの追加ものを論理的に、その思いだけです。
と思い、質問書の書き方のパーサではなく、評価者.というか、どのように表現のツリーから文字列になります。
合計を返す基底クラスなど数です。
の基本構造は、"多様なソリューションが別のように思うのは何を構築することとし、どんな延長することを書き換えることが少なコード可能)がdeserializingオブジェクト階層からのストリーム(躍動)セットされます。
世界の実現の多型解して作成するための方法の表現オブジェクトからパターンを正規表現エンジンがあるのかもしれな列に変換します。にて、 地図BNFまたは類似の書式へのオブジェクト工場とする。
というかこの質問:どのようにすることができます表現(2)BST?この部分は崖っ ます。
再帰.
@ジャスティン:
差し替えによって、様々な注釈を表すノード。ご利用の場合はそのスキーム、
2 + (2)
で表すことができ
.
/ \
2 ( )
|
2
を使用する必要があります機能言語と思う。樹木が難しい表現および操作にOO。
対して人々の関心が集まっていても、ご利用の際は表現で木パーは必要ありません。の業務とな些細な、時にいただいている表現です。のパーはヒントのパーサです。
の受け答えを解決の問題、その他の半分を実際に構文解析表現はまだ未解明であった。通常、これらの問題を解決することができ用 再帰降下パーサ.書などのパーサがしばしばで楽しい運動が 近代ツールの言語の構文解析 ま概要を離れます。
パーサのも 大きく くすことが許されさえすれば、浮動小数点数に文字列になります。あったかをDFAに受け入れ浮動小数点数Cので非常に苦労や詳細な課題です。この有効な浮動小数点を含む:10,10., 10.123,9.876e-5,1.0f.025。ていると思うのであdispensationからこのsimplicty、簡潔っていますが、これらの面接を行います。
長々と書きましたようなパーサの基本技術の
Infix->故 や
シャンヤード や
ツリー Traversals.
ここでは実施いた.
もC++で記述され、統両LinuxやWindowsの場合です。
提案/ご不明な点がございましたら嬉しいです。
うようになったので、問題に対処するためのすべてを生成します。だから演算の表現(例えば文字列)"など2+(2)"を表すツリーをカスケード型の場合、テーブルの機能のポインタ、および/または多型?
これは面白いものにならないと思いこの領域のオブジェクト指向プログラミング...だと思うという 構文解析技術.
私のようなチャッキングはこのc#コンソールアプリとしてビットの証明のコンセプト。って感じです(スイッチ決GetNodeは無骨であるフランス語が堪能な方、是非っ白いマクラス名、オペレーター)).何か改善すべき点も歓迎いたします。
using System;
class Program
{
static void Main(string[] args)
{
string expression = "(((3.5 * 4.5) / (1 + 2)) + 5)";
Console.WriteLine(string.Format("{0} = {1}", expression, new Expression.ExpressionTree(expression).Value));
Console.WriteLine("\nShow's over folks, press a key to exit");
Console.ReadKey(false);
}
}
namespace Expression
{
// -------------------------------------------------------
abstract class NodeBase
{
public abstract double Value { get; }
}
// -------------------------------------------------------
class ValueNode : NodeBase
{
public ValueNode(double value)
{
_double = value;
}
private double _double;
public override double Value
{
get
{
return _double;
}
}
}
// -------------------------------------------------------
abstract class ExpressionNodeBase : NodeBase
{
protected NodeBase GetNode(string expression)
{
// Remove parenthesis
expression = RemoveParenthesis(expression);
// Is expression just a number?
double value = 0;
if (double.TryParse(expression, out value))
{
return new ValueNode(value);
}
else
{
int pos = ParseExpression(expression);
if (pos > 0)
{
string leftExpression = expression.Substring(0, pos - 1).Trim();
string rightExpression = expression.Substring(pos).Trim();
switch (expression.Substring(pos - 1, 1))
{
case "+":
return new Add(leftExpression, rightExpression);
case "-":
return new Subtract(leftExpression, rightExpression);
case "*":
return new Multiply(leftExpression, rightExpression);
case "/":
return new Divide(leftExpression, rightExpression);
default:
throw new Exception("Unknown operator");
}
}
else
{
throw new Exception("Unable to parse expression");
}
}
}
private string RemoveParenthesis(string expression)
{
if (expression.Contains("("))
{
expression = expression.Trim();
int level = 0;
int pos = 0;
foreach (char token in expression.ToCharArray())
{
pos++;
switch (token)
{
case '(':
level++;
break;
case ')':
level--;
break;
}
if (level == 0)
{
break;
}
}
if (level == 0 && pos == expression.Length)
{
expression = expression.Substring(1, expression.Length - 2);
expression = RemoveParenthesis(expression);
}
}
return expression;
}
private int ParseExpression(string expression)
{
int winningLevel = 0;
byte winningTokenWeight = 0;
int winningPos = 0;
int level = 0;
int pos = 0;
foreach (char token in expression.ToCharArray())
{
pos++;
switch (token)
{
case '(':
level++;
break;
case ')':
level--;
break;
}
if (level <= winningLevel)
{
if (OperatorWeight(token) > winningTokenWeight)
{
winningLevel = level;
winningTokenWeight = OperatorWeight(token);
winningPos = pos;
}
}
}
return winningPos;
}
private byte OperatorWeight(char value)
{
switch (value)
{
case '+':
case '-':
return 3;
case '*':
return 2;
case '/':
return 1;
default:
return 0;
}
}
}
// -------------------------------------------------------
class ExpressionTree : ExpressionNodeBase
{
protected NodeBase _rootNode;
public ExpressionTree(string expression)
{
_rootNode = GetNode(expression);
}
public override double Value
{
get
{
return _rootNode.Value;
}
}
}
// -------------------------------------------------------
abstract class OperatorNodeBase : ExpressionNodeBase
{
protected NodeBase _leftNode;
protected NodeBase _rightNode;
public OperatorNodeBase(string leftExpression, string rightExpression)
{
_leftNode = GetNode(leftExpression);
_rightNode = GetNode(rightExpression);
}
}
// -------------------------------------------------------
class Add : OperatorNodeBase
{
public Add(string leftExpression, string rightExpression)
: base(leftExpression, rightExpression)
{
}
public override double Value
{
get
{
return _leftNode.Value + _rightNode.Value;
}
}
}
// -------------------------------------------------------
class Subtract : OperatorNodeBase
{
public Subtract(string leftExpression, string rightExpression)
: base(leftExpression, rightExpression)
{
}
public override double Value
{
get
{
return _leftNode.Value - _rightNode.Value;
}
}
}
// -------------------------------------------------------
class Divide : OperatorNodeBase
{
public Divide(string leftExpression, string rightExpression)
: base(leftExpression, rightExpression)
{
}
public override double Value
{
get
{
return _leftNode.Value / _rightNode.Value;
}
}
}
// -------------------------------------------------------
class Multiply : OperatorNodeBase
{
public Multiply(string leftExpression, string rightExpression)
: base(leftExpression, rightExpression)
{
}
public override double Value
{
get
{
return _leftNode.Value * _rightNode.Value;
}
}
}
}
Ok、こちらのマナーを実施。申し訳なかったのを感じる物をするものです。しさを感じるような悪のウイリーからスティーブの思わなかったです。
#!/usr/bin/env python
#tree structure [left argument, operator, right argument, priority level]
tree_root = [None, None, None, None]
#count of parethesis nesting
parenthesis_level = 0
#current node with empty right argument
current_node = tree_root
#indices in tree_root nodes Left, Operator, Right, PRiority
L, O, R, PR = 0, 1, 2, 3
#functions that realise operators
def sum(a, b):
return a + b
def diff(a, b):
return a - b
def mul(a, b):
return a * b
def div(a, b):
return a / b
#tree evaluator
def process_node(n):
try:
len(n)
except TypeError:
return n
left = process_node(n[L])
right = process_node(n[R])
return n[O](left, right)
#mapping operators to relevant functions
o2f = {'+': sum, '-': diff, '*': mul, '/': div, '(': None, ')': None}
#converts token to a node in tree
def convert_token(t):
global current_node, tree_root, parenthesis_level
if t == '(':
parenthesis_level += 2
return
if t == ')':
parenthesis_level -= 2
return
try: #assumption that we have just an integer
l = int(t)
except (ValueError, TypeError):
pass #if not, no problem
else:
if tree_root[L] is None: #if it is first number, put it on the left of root node
tree_root[L] = l
else: #put on the right of current_node
current_node[R] = l
return
priority = (1 if t in '+-' else 2) + parenthesis_level
#if tree_root does not have operator put it there
if tree_root[O] is None and t in o2f:
tree_root[O] = o2f[t]
tree_root[PR] = priority
return
#if new node has less or equals priority, put it on the top of tree
if tree_root[PR] >= priority:
temp = [tree_root, o2f[t], None, priority]
tree_root = current_node = temp
return
#starting from root search for a place with higher priority in hierarchy
current_node = tree_root
while type(current_node[R]) != type(1) and priority > current_node[R][PR]:
current_node = current_node[R]
#insert new node
temp = [current_node[R], o2f[t], None, priority]
current_node[R] = temp
current_node = temp
def parse(e):
token = ''
for c in e:
if c <= '9' and c >='0':
token += c
continue
if c == ' ':
if token != '':
convert_token(token)
token = ''
continue
if c in o2f:
if token != '':
convert_token(token)
convert_token(c)
token = ''
continue
print "Unrecognized character:", c
if token != '':
convert_token(token)
def main():
parse('(((3 * 4) / (1 + 2)) + 5)')
print tree_root
print process_node(tree_root)
if __name__ == '__main__':
main()