Skip to content

Instantly share code, notes, and snippets.

@RaminHAL9001
Created January 17, 2014 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RaminHAL9001/8480920 to your computer and use it in GitHub Desktop.
Save RaminHAL9001/8480920 to your computer and use it in GitHub Desktop.
BOMDAS, PEMDAS, order of operations. Folding a list of elements where each element is paired with an operator. Providing the operators precedence and associativity, the foldPrec function will infix the elements of the list by the correct order of operations. This is the general case, so it works for anything, not just arithmetic operations.
-- "Data/Function/FoldPrec.hs" fold with precedence and associativity.
--
-- Copyright (C) 2014 Ramin Honary.
--
-- The source code is free software: you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as
-- published by the Free Software Foundation, either version 3 of the
-- License, or (at your option) any later version.
--
-- This software is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
-- <http://www.gnu.org/licenses/agpl.html>.
-- | This modue provides a function 'foldPrec' which folds over a list of operators and operands
-- taking operator precedence and associativity into account.
module Data.Function.FoldPrec where
-- | Every operand must have an integer precedence value assigned to it.
type Precedence = Int
-- | Every operand must have an associativity value assigned to it. 'Prelude.True' indicates a
-- left-associative operator, 'Prelude.False' indicates a right-associative operator.
type Associativity = Bool
-- | Supply a binding function that combines a left-hand and right-hand operand with an infixed
-- operator to produce a new operand.
foldPrec
:: (operand -> operator -> operand -> operand)
-> operand
-> [((operator, Precedence, Associativity), operand)]
-> operand
foldPrec bind left ops = case ops of
[] -> left
((op, prec, _), right):ops -> case scanRight prec right ops of
(right, ops) -> foldPrec bind (bind left op right) ops
where
scanRight prevPrec left ops = case ops of
[] -> (left, [])
((op, prec, assoc), right):next ->
if prevPrec<prec || (prevPrec==prec && not assoc)
then case scanRight prec right next of
(right, next) -> scanRight prevPrec (bind left op right) next
else (left, ops)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment