Skip to content

Instantly share code, notes, and snippets.

@ababup1192
Last active June 8, 2020 20:29
Show Gist options
  • Save ababup1192/3dbd77cba18d2dd0f5d6bb79bfb97709 to your computer and use it in GitHub Desktop.
Save ababup1192/3dbd77cba18d2dd0f5d6bb79bfb97709 to your computer and use it in GitHub Desktop.
RPN(逆ポーランド記法)
module Main exposing (main)
import Browser
import Html exposing (Html, input, main_, p, text)
import Html.Attributes exposing (class, placeholder, value)
import Html.Events exposing (onInput)
-- MAIN
main : Program () Model Msg
main =
Browser.element
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
String
init : () -> ( Model, Cmd Msg )
init _ =
( "", Cmd.none )
-- UPDATE
type Msg
= Change String
update : Msg -> Model -> ( Model, Cmd Msg )
update msg _ =
case msg of
Change poland ->
( poland, Cmd.none )
-- ポーランド記法: "3 4 + 1 2 - *" を Floatに変換。ただし、計算が失敗する可能性も踏まえて Maybe Float とする。
-- 勝手に例外を吐かずに、計算失敗性も考慮するのがElm流(そのため最初は少し面倒で難しいかもだが・・・)
calc : String -> Maybe Float
calc poland =
-- stackの最後に数値が一つだけ残ったら、その先頭を取得。 [ 3.0 ] -> Just 3.0, [] -> Nothing
List.head <|
-- 逆ポーランド記法から1つずつトークンを読み込み、計算用stackに積み上げていく(畳み込み)
List.foldl
(\token stack ->
case ( stack, token ) of
-- トークンが演算子(+, -, *, /)だったら、stackの先頭2つの数字を取り出し(pop, pop)、計算結果をstackに積む
( x :: y :: ys, "+" ) ->
(y + x) :: ys
( x :: y :: ys, "-" ) ->
(y - x) :: ys
( x :: y :: ys, "*" ) ->
(y * x) :: ys
( x :: y :: ys, "/" ) ->
(y / x) :: ys
( xs, numString ) ->
-- tokenが数値(文字列) であれば、変換する
case String.toFloat numString of
Just num ->
num :: xs
-- 変換に失敗したら(数値以外の文字列であれば)、stackは空にして計算を失敗させる
Nothing ->
[]
)
-- 計算用stack, 最初は空
[]
-- ポーランド記法: "3 4 + 1 2 - *" を トークン列: ["3", "4", "+", "1", "2", "-", "*"] に変換
(String.split " " poland)
view : Model -> Html Msg
view model =
main_ [ class "ly_cont" ]
[ input [ value model, onInput Change, placeholder "10 4 3 + 2 * -" ] []
-- ポーランド記法(model)の計算し、FloatからStringへ変換。ただし計算に失敗していたら"error"と表示する。
, p [] [ text <| Maybe.withDefault "error" <| Maybe.map String.fromFloat <| calc model ]
]
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment