Skip to content

Instantly share code, notes, and snippets.

@rupertlssmith
Created June 12, 2018 10:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rupertlssmith/fe24d4f740fa9b622a3c329fc2330772 to your computer and use it in GitHub Desktop.
Save rupertlssmith/fe24d4f740fa9b622a3c329fc2330772 to your computer and use it in GitHub Desktop.
Traits in Elm
module Traits exposing (..)
type GameState
= State
{-| FireTrait defines how the game state is updated for any kind of shooting
event.
's' is the state implementation parameter,
'a' makes the trait extensible so that traits can be combined.
-}
type alias FireTrait s a =
{ a
| fire : s -> GameState -> GameState
}
type alias Gun a =
{ a
| power : Float
, turretSize : Int
}
{-| A castle has a gun and a shield.
-}
type alias Castle =
Gun { shield : Float }
{-| A zap monster has a gun and health and a special zapping power.
-}
type alias ZapMonster =
Gun
{ health : Float
, zapPower : Float
}
type alias CastleTraits =
FireTrait Castle {}
type alias ZapMonsterTraits =
FireTrait ZapMonster {}
{-| How to update the game state when a gun is fired - only needs to be written once.
-}
fireGun : Gun a -> GameState -> GameState
fireGun _ state =
state
{-| How to update the game state for any firing trait - only needs to be written once.
-}
updateForFiring : FireTrait s a -> s -> GameState -> GameState
updateForFiring fireTrait gameObject state =
fireTrait.fire gameObject state
-- Example with castles and zap monsters both with normal guns.
castleTraits : CastleTraits
castleTraits =
{ fire = fireGun }
zapMonsterTraits : ZapMonsterTraits
zapMonsterTraits =
{ fire = fireGun }
castle : Castle
castle =
{ power = 100, turretSize = 5, shield = 100 }
zapMonster : ZapMonster
zapMonster =
{ power = 60, turretSize = 2, health = 100, zapPower = 20 }
gameState1 =
updateForFiring castleTraits castle State
gameState2 =
updateForFiring zapMonsterTraits zapMonster gameState1
-- Example with a zap monster upgraded to use its special zap ability.
-- A new fire implementation is written, but the existing update logic is
-- re-used as it was coded for the general trait.
fireZap : ZapMonster -> GameState -> GameState
fireZap _ state =
state
zapMonsterTraits2 : ZapMonsterTraits
zapMonsterTraits2 =
{ fire = fireZap }
gameState3 =
updateForFiring zapMonsterTraits2 zapMonster gameState2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment