VOTING POWER100.00%
DOWNVOTE POWER100.00%
RESOURCE CREDITS100.00%
REPUTATION PROGRESS0.00%
Net Worth
0.008USD
STEEM
0.032STEEM
SBD
0.000SBD
Effective Power
5.001SP
├── Own SP
0.124SP
└── Incoming DelegationsDeleg
+4.877SP
Detailed Balance
| STEEM | ||
| balance | 0.000STEEM | STEEM |
| market_balance | 0.000STEEM | STEEM |
| savings_balance | 0.000STEEM | STEEM |
| reward_steem_balance | 0.032STEEM | STEEM |
| STEEM POWER | ||
| Own SP | 0.124SP | SP |
| Delegated Out | 0.000SP | SP |
| Delegation In | 4.877SP | SP |
| Effective Power | 5.001SP | SP |
| Reward SP (pending) | 0.033SP | SP |
| SBD | ||
| sbd_balance | 0.000SBD | SBD |
| sbd_conversions | 0.000SBD | SBD |
| sbd_market_balance | 0.000SBD | SBD |
| savings_sbd_balance | 0.000SBD | SBD |
| reward_sbd_balance | 0.000SBD | SBD |
{
"balance": "0.000 STEEM",
"savings_balance": "0.000 STEEM",
"reward_steem_balance": "0.032 STEEM",
"vesting_shares": "202.526059 VESTS",
"delegated_vesting_shares": "0.000000 VESTS",
"received_vesting_shares": "7941.133747 VESTS",
"sbd_balance": "0.000 SBD",
"savings_sbd_balance": "0.000 SBD",
"reward_sbd_balance": "0.000 SBD",
"conversions": []
}Account Info
| name | aas-sh |
| id | 1102733 |
| rank | 268,818 |
| reputation | 957177129 |
| created | 2018-08-14T15:38:48 |
| recovery_account | steem |
| proxy | None |
| post_count | 7 |
| comment_count | 0 |
| lifetime_vote_count | 0 |
| witnesses_voted_for | 1 |
| last_post | 2018-09-11T16:52:06 |
| last_root_post | 2018-09-11T16:52:06 |
| last_vote_time | 2018-09-11T16:58:00 |
| proxied_vsf_votes | 0, 0, 0, 0 |
| can_vote | 1 |
| voting_power | 0 |
| delayed_votes | 0 |
| balance | 0.000 STEEM |
| savings_balance | 0.000 STEEM |
| sbd_balance | 0.000 SBD |
| savings_sbd_balance | 0.000 SBD |
| vesting_shares | 202.526059 VESTS |
| delegated_vesting_shares | 0.000000 VESTS |
| received_vesting_shares | 7941.133747 VESTS |
| reward_vesting_balance | 66.802480 VESTS |
| vesting_balance | 0.000 STEEM |
| vesting_withdraw_rate | 0.000000 VESTS |
| next_vesting_withdrawal | 1969-12-31T23:59:59 |
| withdrawn | 0 |
| to_withdraw | 0 |
| withdraw_routes | 0 |
| savings_withdraw_requests | 0 |
| last_account_recovery | 1970-01-01T00:00:00 |
| reset_account | null |
| last_owner_update | 1970-01-01T00:00:00 |
| last_account_update | 2022-01-09T16:38:30 |
| mined | No |
| sbd_seconds | 0 |
| sbd_last_interest_payment | 1970-01-01T00:00:00 |
| savings_sbd_last_interest_payment | 1970-01-01T00:00:00 |
{
"id": 1102733,
"name": "aas-sh",
"owner": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM8cWUTvpJwtKkvLJ5AQ5iKZhFWJBKBdAUXub6nr2RZ7vRcFKPzR",
1
]
]
},
"active": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM5gXLneWqCr3hiUEcRUfgWBo8U4ktdbF8hLvqctqMB9ZznNNJJA",
1
]
]
},
"posting": {
"weight_threshold": 1,
"account_auths": [
[
"finally.app",
1
]
],
"key_auths": [
[
"STM8eaB64qVgR4N7do5HVZVxPPg6afRt4ZcMQ3DY989zS9f4LxrdD",
1
]
]
},
"memo_key": "STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6",
"json_metadata": "{\"profile\":{\"cover_image\":\"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg\",\"name\":\"Ashe\",\"about\":\"Ambitious CS Student and indie games developer\",\"location\":\"Sheffield, UK\",\"website\":\"https://aas.sh\",\"profile_image\":\"https://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg\"}}",
"posting_json_metadata": "{\"profile\":{\"name\":\"Ashe\",\"website\":\"https://aas.sh\",\"version\":2}}",
"proxy": "",
"last_owner_update": "1970-01-01T00:00:00",
"last_account_update": "2022-01-09T16:38:30",
"created": "2018-08-14T15:38:48",
"mined": false,
"recovery_account": "steem",
"last_account_recovery": "1970-01-01T00:00:00",
"reset_account": "null",
"comment_count": 0,
"lifetime_vote_count": 0,
"post_count": 7,
"can_vote": true,
"voting_manabar": {
"current_mana": "8143659806",
"last_update_time": 1779050811
},
"downvote_manabar": {
"current_mana": 2035914951,
"last_update_time": 1779050811
},
"voting_power": 0,
"balance": "0.000 STEEM",
"savings_balance": "0.000 STEEM",
"sbd_balance": "0.000 SBD",
"sbd_seconds": "0",
"sbd_seconds_last_update": "1970-01-01T00:00:00",
"sbd_last_interest_payment": "1970-01-01T00:00:00",
"savings_sbd_balance": "0.000 SBD",
"savings_sbd_seconds": "0",
"savings_sbd_seconds_last_update": "1970-01-01T00:00:00",
"savings_sbd_last_interest_payment": "1970-01-01T00:00:00",
"savings_withdraw_requests": 0,
"reward_sbd_balance": "0.000 SBD",
"reward_steem_balance": "0.032 STEEM",
"reward_vesting_balance": "66.802480 VESTS",
"reward_vesting_steem": "0.033 STEEM",
"vesting_shares": "202.526059 VESTS",
"delegated_vesting_shares": "0.000000 VESTS",
"received_vesting_shares": "7941.133747 VESTS",
"vesting_withdraw_rate": "0.000000 VESTS",
"next_vesting_withdrawal": "1969-12-31T23:59:59",
"withdrawn": 0,
"to_withdraw": 0,
"withdraw_routes": 0,
"curation_rewards": 0,
"posting_rewards": 65,
"proxied_vsf_votes": [
0,
0,
0,
0
],
"witnesses_voted_for": 1,
"last_post": "2018-09-11T16:52:06",
"last_root_post": "2018-09-11T16:52:06",
"last_vote_time": "2018-09-11T16:58:00",
"post_bandwidth": 0,
"pending_claimed_accounts": 0,
"vesting_balance": "0.000 STEEM",
"reputation": 957177129,
"transfer_history": [],
"market_history": [],
"post_history": [],
"vote_history": [],
"other_history": [],
"witness_votes": [
"steemitboard"
],
"tags_usage": [],
"guest_bloggers": [],
"rank": 268818
}Withdraw Routes
| Incoming | Outgoing |
|---|---|
Empty | Empty |
{
"incoming": [],
"outgoing": []
}From Date
To Date
2026/05/17 20:46:51
2026/05/17 20:46:51
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 7941.133747 VESTS |
| Transaction Info | Block #106139299/Trx dd927f716740687f294709f660450fa14dadbd6f |
View Raw JSON Data
{
"trx_id": "dd927f716740687f294709f660450fa14dadbd6f",
"block": 106139299,
"trx_in_block": 0,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2026-05-17T20:46:51",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "7941.133747 VESTS"
}
]
}2026/05/11 16:08:36
2026/05/11 16:08:36
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 5228.923342 VESTS |
| Transaction Info | Block #105961715/Trx 69cfab710d03b6c554971d44a973311d82d98cd2 |
View Raw JSON Data
{
"trx_id": "69cfab710d03b6c554971d44a973311d82d98cd2",
"block": 105961715,
"trx_in_block": 4,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2026-05-11T16:08:36",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "5228.923342 VESTS"
}
]
}2026/04/25 20:13:06
2026/04/25 20:13:06
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 7953.649503 VESTS |
| Transaction Info | Block #105507048/Trx d0d3c82a73224e329d5c425780ce41e7a29a995a |
View Raw JSON Data
{
"trx_id": "d0d3c82a73224e329d5c425780ce41e7a29a995a",
"block": 105507048,
"trx_in_block": 0,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2026-04-25T20:13:06",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "7953.649503 VESTS"
}
]
}2026/01/22 22:28:48
2026/01/22 22:28:48
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 5270.470161 VESTS |
| Transaction Info | Block #102840647/Trx bd34303a02dea845d9d05991a24abd5139a3db98 |
View Raw JSON Data
{
"trx_id": "bd34303a02dea845d9d05991a24abd5139a3db98",
"block": 102840647,
"trx_in_block": 2,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2026-01-22T22:28:48",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "5270.470161 VESTS"
}
]
}2024/12/16 17:50:12
2024/12/16 17:50:12
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 5434.689358 VESTS |
| Transaction Info | Block #91287100/Trx 1d48ae54c325d0d9336774b9427fbe1cf04c0f55 |
View Raw JSON Data
{
"trx_id": "1d48ae54c325d0d9336774b9427fbe1cf04c0f55",
"block": 91287100,
"trx_in_block": 1,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2024-12-16T17:50:12",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "5434.689358 VESTS"
}
]
}2023/11/13 09:35:57
2023/11/13 09:35:57
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 5603.825804 VESTS |
| Transaction Info | Block #79841380/Trx c3250a509fb870ec5cd8870854cee930d032ac9e |
View Raw JSON Data
{
"trx_id": "c3250a509fb870ec5cd8870854cee930d032ac9e",
"block": 79841380,
"trx_in_block": 6,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2023-11-13T09:35:57",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "5603.825804 VESTS"
}
]
}2023/09/21 17:43:51
2023/09/21 17:43:51
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 8541.101676 VESTS |
| Transaction Info | Block #78342929/Trx 262f983107a206cfb885ead64845c8572348a70c |
View Raw JSON Data
{
"trx_id": "262f983107a206cfb885ead64845c8572348a70c",
"block": 78342929,
"trx_in_block": 1,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2023-09-21T17:43:51",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "8541.101676 VESTS"
}
]
}2022/11/03 08:00:09
2022/11/03 08:00:09
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 8762.783114 VESTS |
| Transaction Info | Block #69108838/Trx 736be2fe4f4c473e3717909792ab1c038226a2aa |
View Raw JSON Data
{
"trx_id": "736be2fe4f4c473e3717909792ab1c038226a2aa",
"block": 69108838,
"trx_in_block": 4,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2022-11-03T08:00:09",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "8762.783114 VESTS"
}
]
}2022/01/17 07:37:33
2022/01/17 07:37:33
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 8983.316345 VESTS |
| Transaction Info | Block #60805441/Trx cc984547496222f43774fc8055c37d45d395d2e9 |
View Raw JSON Data
{
"trx_id": "cc984547496222f43774fc8055c37d45d395d2e9",
"block": 60805441,
"trx_in_block": 11,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2022-01-17T07:37:33",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "8983.316345 VESTS"
}
]
}aas-shupdated their account properties2022/01/09 16:38:30
aas-shupdated their account properties
2022/01/09 16:38:30
| account | aas-sh |
| json metadata | |
| posting json metadata | {"profile":{"name":"Ashe","website":"https://aas.sh","version":2}} |
| extensions | [] |
| Transaction Info | Block #60587036/Trx 09cc09a9cde4cd72ad59bcb683fe4588bf06e44b |
View Raw JSON Data
{
"trx_id": "09cc09a9cde4cd72ad59bcb683fe4588bf06e44b",
"block": 60587036,
"trx_in_block": 36,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2022-01-09T16:38:30",
"op": [
"account_update2",
{
"account": "aas-sh",
"json_metadata": "",
"posting_json_metadata": "{\"profile\":{\"name\":\"Ashe\",\"website\":\"https://aas.sh\",\"version\":2}}",
"extensions": []
}
]
}aas-shupdated their account properties2022/01/09 16:38:15
aas-shupdated their account properties
2022/01/09 16:38:15
| account | aas-sh |
| json metadata | |
| posting json metadata | {"profile":{"name":"Ashe","website":"https://aas.sh","version":2,"profile_image":"https://cdn.steemitimages.com/DQmRHc4MJH9xeudWQvciSNQgahHz3FCec36vAMHEmbMoxMN/logo.png"}} |
| extensions | [] |
| Transaction Info | Block #60587031/Trx 2c7b8e416e05f339efddeee97f60312f6c92f173 |
View Raw JSON Data
{
"trx_id": "2c7b8e416e05f339efddeee97f60312f6c92f173",
"block": 60587031,
"trx_in_block": 4,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2022-01-09T16:38:15",
"op": [
"account_update2",
{
"account": "aas-sh",
"json_metadata": "",
"posting_json_metadata": "{\"profile\":{\"name\":\"Ashe\",\"website\":\"https://aas.sh\",\"version\":2,\"profile_image\":\"https://cdn.steemitimages.com/DQmRHc4MJH9xeudWQvciSNQgahHz3FCec36vAMHEmbMoxMN/logo.png\"}}",
"extensions": []
}
]
}aas-shupdated their account properties2022/01/09 16:36:18
aas-shupdated their account properties
2022/01/09 16:36:18
| account | aas-sh |
| json metadata | |
| posting json metadata | {"profile":{"cover_image":"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg","name":"Ashe","about":"Ambitious CS Student and indie games developer","location":"Sheffield, UK","website":"https://aas.sh","version":2}} |
| extensions | [] |
| Transaction Info | Block #60586993/Trx 3de9db7577a74b516d397ace872bba658dcac459 |
View Raw JSON Data
{
"trx_id": "3de9db7577a74b516d397ace872bba658dcac459",
"block": 60586993,
"trx_in_block": 0,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2022-01-09T16:36:18",
"op": [
"account_update2",
{
"account": "aas-sh",
"json_metadata": "",
"posting_json_metadata": "{\"profile\":{\"cover_image\":\"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg\",\"name\":\"Ashe\",\"about\":\"Ambitious CS Student and indie games developer\",\"location\":\"Sheffield, UK\",\"website\":\"https://aas.sh\",\"version\":2}}",
"extensions": []
}
]
}2021/06/13 21:41:12
2021/06/13 21:41:12
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 9167.085003 VESTS |
| Transaction Info | Block #54603999/Trx 4fb606826e0b6d9f65c117d4a8a829034ef038a7 |
View Raw JSON Data
{
"trx_id": "4fb606826e0b6d9f65c117d4a8a829034ef038a7",
"block": 54603999,
"trx_in_block": 9,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2021-06-13T21:41:12",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "9167.085003 VESTS"
}
]
}2020/12/11 08:04:45
2020/12/11 08:04:45
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 9354.506977 VESTS |
| Transaction Info | Block #49351590/Trx 12b34d42c980dad2f46c7fa11553b250ee3a886c |
View Raw JSON Data
{
"trx_id": "12b34d42c980dad2f46c7fa11553b250ee3a886c",
"block": 49351590,
"trx_in_block": 2,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2020-12-11T08:04:45",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "9354.506977 VESTS"
}
]
}2020/12/06 01:42:06
2020/12/06 01:42:06
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 1912.543513 VESTS |
| Transaction Info | Block #49203157/Trx c7cc604aa29b5d19b3c8e61c1210ff63cc0f495a |
View Raw JSON Data
{
"trx_id": "c7cc604aa29b5d19b3c8e61c1210ff63cc0f495a",
"block": 49203157,
"trx_in_block": 0,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2020-12-06T01:42:06",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "1912.543513 VESTS"
}
]
}2020/11/25 14:22:27
2020/11/25 14:22:27
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 9371.633594 VESTS |
| Transaction Info | Block #48906009/Trx 1da45fe3ff620c6a05f57791fbc272ac26e00904 |
View Raw JSON Data
{
"trx_id": "1da45fe3ff620c6a05f57791fbc272ac26e00904",
"block": 48906009,
"trx_in_block": 1,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2020-11-25T14:22:27",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "9371.633594 VESTS"
}
]
}2020/05/09 02:36:36
2020/05/09 02:36:36
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 9563.520190 VESTS |
| Transaction Info | Block #43213369/Trx 629445482543ae105d4a719e6580812af7fabe32 |
View Raw JSON Data
{
"trx_id": "629445482543ae105d4a719e6580812af7fabe32",
"block": 43213369,
"trx_in_block": 0,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2020-05-09T02:36:36",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "9563.520190 VESTS"
}
]
}2020/05/08 05:44:00
2020/05/08 05:44:00
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 1953.311140 VESTS |
| Transaction Info | Block #43188902/Trx b19730ad465d459ba3bcd38b02d119bba3777062 |
View Raw JSON Data
{
"trx_id": "b19730ad465d459ba3bcd38b02d119bba3777062",
"block": 43188902,
"trx_in_block": 17,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2020-05-08T05:44:00",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "1953.311140 VESTS"
}
]
}2019/11/15 08:44:09
2019/11/15 08:44:09
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 9661.615441 VESTS |
| Transaction Info | Block #38191674/Trx b08095650aeb529c5f68279ecdaeccfea5b1164a |
View Raw JSON Data
{
"trx_id": "b08095650aeb529c5f68279ecdaeccfea5b1164a",
"block": 38191674,
"trx_in_block": 8,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2019-11-15T08:44:09",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "9661.615441 VESTS"
}
]
}2019/08/14 16:37:39
2019/08/14 16:37:39
| parent author | aas-sh |
| parent permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| author | steemitboard |
| permlink | steemitboard-notify-aas-sh-20190814t163738000z |
| title | |
| body | Congratulations @aas-sh! You received a personal award! <table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@aas-sh/birthday1.png</td><td>Happy Birthday! - You are on the Steem blockchain for 1 year!</td></tr></table> <sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@aas-sh) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=aas-sh)_</sub> > You can upvote this notification to help all Steem users. Learn how [here](https://steemit.com/steemitboard/@steemitboard/http-i-cubeupload-com-7ciqeo-png)! |
| json metadata | {"image":["https://steemitboard.com/img/notify.png"]} |
| Transaction Info | Block #35549954/Trx 385668ce04972591480a36da69aaa0c7598e5b78 |
View Raw JSON Data
{
"trx_id": "385668ce04972591480a36da69aaa0c7598e5b78",
"block": 35549954,
"trx_in_block": 3,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2019-08-14T16:37:39",
"op": [
"comment",
{
"parent_author": "aas-sh",
"parent_permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"author": "steemitboard",
"permlink": "steemitboard-notify-aas-sh-20190814t163738000z",
"title": "",
"body": "Congratulations @aas-sh! You received a personal award!\n\n<table><tr><td>https://steemitimages.com/70x70/http://steemitboard.com/@aas-sh/birthday1.png</td><td>Happy Birthday! - You are on the Steem blockchain for 1 year!</td></tr></table>\n\n<sub>_You can view [your badges on your Steem Board](https://steemitboard.com/@aas-sh) and compare to others on the [Steem Ranking](https://steemitboard.com/ranking/index.php?name=aas-sh)_</sub>\n\n\n> You can upvote this notification to help all Steem users. Learn how [here](https://steemit.com/steemitboard/@steemitboard/http-i-cubeupload-com-7ciqeo-png)!",
"json_metadata": "{\"image\":[\"https://steemitboard.com/img/notify.png\"]}"
}
]
}2018/12/11 17:24:45
2018/12/11 17:24:45
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 9858.945320 VESTS |
| Transaction Info | Block #28475634/Trx 69a6737da39dcace321f5981d73005a832fb44ee |
View Raw JSON Data
{
"trx_id": "69a6737da39dcace321f5981d73005a832fb44ee",
"block": 28475634,
"trx_in_block": 15,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-12-11T17:24:45",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "9858.945320 VESTS"
}
]
}ratxueupvoted (100.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs2018/10/22 02:43:06
ratxueupvoted (100.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs
2018/10/22 02:43:06
| voter | ratxue |
| author | aas-sh |
| permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| weight | 10000 (100.00%) |
| Transaction Info | Block #27018896/Trx d5ed83fd413313d7abe1b3ec2ef4e468c4081c42 |
View Raw JSON Data
{
"trx_id": "d5ed83fd413313d7abe1b3ec2ef4e468c4081c42",
"block": 27018896,
"trx_in_block": 29,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-10-22T02:43:06",
"op": [
"vote",
{
"voter": "ratxue",
"author": "aas-sh",
"permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"weight": 10000
}
]
}2018/10/08 15:30:15
2018/10/08 15:30:15
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 30087.518713 VESTS |
| Transaction Info | Block #26631329/Trx 499c877872d72f95b425f8d419ad8e5609526f21 |
View Raw JSON Data
{
"trx_id": "499c877872d72f95b425f8d419ad8e5609526f21",
"block": 26631329,
"trx_in_block": 17,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-10-08T15:30:15",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "30087.518713 VESTS"
}
]
}2018/09/26 16:34:39
2018/09/26 16:34:39
| delegator | steem |
| delegatee | aas-sh |
| vesting shares | 60619.029150 VESTS |
| Transaction Info | Block #26287281/Trx e097d951e9740f7d8366377894ec42d3134ad399 |
View Raw JSON Data
{
"trx_id": "e097d951e9740f7d8366377894ec42d3134ad399",
"block": 26287281,
"trx_in_block": 12,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-26T16:34:39",
"op": [
"delegate_vesting_shares",
{
"delegator": "steem",
"delegatee": "aas-sh",
"vesting_shares": "60619.029150 VESTS"
}
]
}sensationupvoted (100.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs2018/09/11 17:55:57
sensationupvoted (100.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs
2018/09/11 17:55:57
| voter | sensation |
| author | aas-sh |
| permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25872867/Trx 770e757c15fc32c468fd333017bf71df057fb8bf |
View Raw JSON Data
{
"trx_id": "770e757c15fc32c468fd333017bf71df057fb8bf",
"block": 25872867,
"trx_in_block": 0,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T17:55:57",
"op": [
"vote",
{
"voter": "sensation",
"author": "aas-sh",
"permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"weight": 10000
}
]
}moby-dickupvoted (100.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs2018/09/11 17:47:18
moby-dickupvoted (100.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs
2018/09/11 17:47:18
| voter | moby-dick |
| author | aas-sh |
| permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25872694/Trx 0879d15947168712ae129068be15e42f42b9cba9 |
View Raw JSON Data
{
"trx_id": "0879d15947168712ae129068be15e42f42b9cba9",
"block": 25872694,
"trx_in_block": 5,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T17:47:18",
"op": [
"vote",
{
"voter": "moby-dick",
"author": "aas-sh",
"permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"weight": 10000
}
]
}aas-shupvoted (100.00%) @ilovecoding / 20180911t165221532z2018/09/11 16:58:00
aas-shupvoted (100.00%) @ilovecoding / 20180911t165221532z
2018/09/11 16:58:00
| voter | aas-sh |
| author | ilovecoding |
| permlink | 20180911t165221532z |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25871708/Trx 388a267872be5ab45a5277f4174c2f6af223d12b |
View Raw JSON Data
{
"trx_id": "388a267872be5ab45a5277f4174c2f6af223d12b",
"block": 25871708,
"trx_in_block": 12,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:58:00",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "ilovecoding",
"permlink": "20180911t165221532z",
"weight": 10000
}
]
}aas-shmuted @grammarnazi2018/09/11 16:56:18
aas-shmuted @grammarnazi
2018/09/11 16:56:18
| required auths | [] |
| required posting auths | ["aas-sh"] |
| id | follow |
| json | ["follow",{"follower":"aas-sh","following":"grammarnazi","what":["ignore"]}] |
| Transaction Info | Block #25871674/Trx c82822df6240435868589af6f3aa15176b018f84 |
View Raw JSON Data
{
"trx_id": "c82822df6240435868589af6f3aa15176b018f84",
"block": 25871674,
"trx_in_block": 43,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:56:18",
"op": [
"custom_json",
{
"required_auths": [],
"required_posting_auths": [
"aas-sh"
],
"id": "follow",
"json": "[\"follow\",{\"follower\":\"aas-sh\",\"following\":\"grammarnazi\",\"what\":[\"ignore\"]}]"
}
]
}aas-shpublished a new post: an-introduction-to-developing-games-in-haskell-with-apecs2018/09/11 16:55:57
aas-shpublished a new post: an-introduction-to-developing-games-in-haskell-with-apecs
2018/09/11 16:55:57
| parent author | |
| parent permlink | blog |
| author | aas-sh |
| permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| title | An Introduction to Developing games in Haskell with Apecs |
| body | @@ -11480,16 +11480,17 @@ he occur +r ence of |
| json metadata | {"tags":["blog","programming","haskell","guide","games"],"links":["https://blog.aas.sh/posts/2018-09-10-Making-A-Game-With-Haskell-And-Apecs/","https://blog.aas.sh/posts/2018-06-09-Of-Boxes-And-Threads/","http://haskellbook.com/","https://docs.haskellstack.org/en/stable/README/","https://www.stackage.org/","https://github.com/ghcjs/ghcjs","https://hackage.haskell.org/package/apecs","https://hackage.haskell.org/package/sdl2","https://hackage.haskell.org/package/SDL-ttf","https://hackage.haskell.org/package/SDL-image","https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Time.html#v:delay","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:makeWorld","https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Framerate.html","https://en.wikipedia.org/wiki/Delta_timing","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:runSystem","https://wiki.haskell.org/Constructor","https://hackage.haskell.org/package/linear","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Stores.html","https://wiki.haskell.org/Orphan_instance","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-System.html","https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Core.html#t:SystemT","https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Event.html#t:EventPayload","https://store.steampowered.com/app/497800/Golden_Krone_Hotel/"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25871667/Trx d435590762a6d89068add24efb921413805ab004 |
View Raw JSON Data
{
"trx_id": "d435590762a6d89068add24efb921413805ab004",
"block": 25871667,
"trx_in_block": 23,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:55:57",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "blog",
"author": "aas-sh",
"permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"title": "An Introduction to Developing games in Haskell with Apecs",
"body": "@@ -11480,16 +11480,17 @@\n he occur\n+r\n ence of \n",
"json_metadata": "{\"tags\":[\"blog\",\"programming\",\"haskell\",\"guide\",\"games\"],\"links\":[\"https://blog.aas.sh/posts/2018-09-10-Making-A-Game-With-Haskell-And-Apecs/\",\"https://blog.aas.sh/posts/2018-06-09-Of-Boxes-And-Threads/\",\"http://haskellbook.com/\",\"https://docs.haskellstack.org/en/stable/README/\",\"https://www.stackage.org/\",\"https://github.com/ghcjs/ghcjs\",\"https://hackage.haskell.org/package/apecs\",\"https://hackage.haskell.org/package/sdl2\",\"https://hackage.haskell.org/package/SDL-ttf\",\"https://hackage.haskell.org/package/SDL-image\",\"https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Time.html#v:delay\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:makeWorld\",\"https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Framerate.html\",\"https://en.wikipedia.org/wiki/Delta_timing\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:runSystem\",\"https://wiki.haskell.org/Constructor\",\"https://hackage.haskell.org/package/linear\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Stores.html\",\"https://wiki.haskell.org/Orphan_instance\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-System.html\",\"https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Core.html#t:SystemT\",\"https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Event.html#t:EventPayload\",\"https://store.steampowered.com/app/497800/Golden_Krone_Hotel/\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}ilovecodingreplied to @aas-sh / 20180911t165221532z2018/09/11 16:52:21
ilovecodingreplied to @aas-sh / 20180911t165221532z
2018/09/11 16:52:21
| parent author | aas-sh |
| parent permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| author | ilovecoding |
| permlink | 20180911t165221532z |
| title | |
| body | Hello! Your post has been resteemed and upvoted by @ilovecoding because **we love coding**! Keep up good work! Consider upvoting this comment to support the @ilovecoding and increase your future rewards! ^_^ Steem On!  *Reply !stop to disable the comment. Thanks!* |
| json metadata | {"tags":["ilovecoding"],"app":"ilovecoding"} |
| Transaction Info | Block #25871595/Trx 0d128112ffec20e7928702660b888a746110f700 |
View Raw JSON Data
{
"trx_id": "0d128112ffec20e7928702660b888a746110f700",
"block": 25871595,
"trx_in_block": 21,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:52:21",
"op": [
"comment",
{
"parent_author": "aas-sh",
"parent_permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"author": "ilovecoding",
"permlink": "20180911t165221532z",
"title": "",
"body": "Hello! Your post has been resteemed and upvoted by @ilovecoding because **we love coding**! Keep up good work! Consider upvoting this comment to support the @ilovecoding and increase your future rewards! ^_^ Steem On! \n  \n*Reply !stop to disable the comment. Thanks!*",
"json_metadata": "{\"tags\":[\"ilovecoding\"],\"app\":\"ilovecoding\"}"
}
]
}ilovecodingupvoted (10.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs2018/09/11 16:52:18
ilovecodingupvoted (10.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs
2018/09/11 16:52:18
| voter | ilovecoding |
| author | aas-sh |
| permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| weight | 1000 (10.00%) |
| Transaction Info | Block #25871594/Trx 31f0d9d671b6dd1b0cb05f8f77f59874417e6a6e |
View Raw JSON Data
{
"trx_id": "31f0d9d671b6dd1b0cb05f8f77f59874417e6a6e",
"block": 25871594,
"trx_in_block": 41,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:52:18",
"op": [
"vote",
{
"voter": "ilovecoding",
"author": "aas-sh",
"permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"weight": 1000
}
]
}grammarnaziupvoted (50.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs2018/09/11 16:52:15
grammarnaziupvoted (50.00%) @aas-sh / an-introduction-to-developing-games-in-haskell-with-apecs
2018/09/11 16:52:15
| voter | grammarnazi |
| author | aas-sh |
| permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| weight | 5000 (50.00%) |
| Transaction Info | Block #25871593/Trx 42c1f9f98959eececa70a60ca98e06b4512e2769 |
View Raw JSON Data
{
"trx_id": "42c1f9f98959eececa70a60ca98e06b4512e2769",
"block": 25871593,
"trx_in_block": 0,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:52:15",
"op": [
"vote",
{
"voter": "grammarnazi",
"author": "aas-sh",
"permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"weight": 5000
}
]
}2018/09/11 16:52:09
2018/09/11 16:52:09
| parent author | aas-sh |
| parent permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| author | grammarnazi |
| permlink | re-aas-sh-an-introduction-to-developing-games-in-haskell-with-apecs-20180911t165202237z |
| title | Minor Correction |
| body | You have a minor misspelling in the following sentence: <blockquote> You can replace the occurence of your type with what it represents, it does nothing else.</blockquote> It should be <i>occurrence</i> instead of <i>occurence</i>. |
| json metadata | {"app":"steemit"} |
| Transaction Info | Block #25871591/Trx 19c24848547eeff0eabe242586d61db493ceb440 |
View Raw JSON Data
{
"trx_id": "19c24848547eeff0eabe242586d61db493ceb440",
"block": 25871591,
"trx_in_block": 19,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:52:09",
"op": [
"comment",
{
"parent_author": "aas-sh",
"parent_permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"author": "grammarnazi",
"permlink": "re-aas-sh-an-introduction-to-developing-games-in-haskell-with-apecs-20180911t165202237z",
"title": "Minor Correction",
"body": "You have a minor misspelling in the following sentence: <blockquote> You can replace the occurence of your type with what it represents, it does nothing else.</blockquote> It should be <i>occurrence</i> instead of <i>occurence</i>.",
"json_metadata": "{\"app\":\"steemit\"}"
}
]
}2018/09/11 16:52:09
2018/09/11 16:52:09
| parent author | aas-sh |
| parent permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| author | grammarnazi |
| permlink | re-aas-sh-an-introduction-to-developing-games-in-haskell-with-apecs-20180911t165202237z |
| title | Minor Correction |
| body | You have a minor misspelling in the following sentence: <blockquote> Normally in C++ or C#, I'd make my ECS seperate from a few things baked into the engine, but with Apecs I have to imagine a lot of things as a global component instead.</blockquote> It should be <i>separate</i> instead of <i>seperate</i>. |
| json metadata | {"app":"steemit"} |
| Transaction Info | Block #25871591/Trx 7cdf8193de4f6fa824f98ea4f0f22656043a3281 |
View Raw JSON Data
{
"trx_id": "7cdf8193de4f6fa824f98ea4f0f22656043a3281",
"block": 25871591,
"trx_in_block": 18,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:52:09",
"op": [
"comment",
{
"parent_author": "aas-sh",
"parent_permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"author": "grammarnazi",
"permlink": "re-aas-sh-an-introduction-to-developing-games-in-haskell-with-apecs-20180911t165202237z",
"title": "Minor Correction",
"body": "You have a minor misspelling in the following sentence: <blockquote> Normally in C++ or C#, I'd make my ECS seperate from a few things baked into the engine, but with Apecs I have to imagine a lot of things as a global component instead.</blockquote> It should be <i>separate</i> instead of <i>seperate</i>.",
"json_metadata": "{\"app\":\"steemit\"}"
}
]
}2018/09/11 16:52:09
2018/09/11 16:52:09
| parent author | aas-sh |
| parent permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| author | grammarnazi |
| permlink | re-aas-sh-an-introduction-to-developing-games-in-haskell-with-apecs-20180911t165202237z |
| title | Minor Correction |
| body | You have a minor grammatical mistake in the following sentence: <blockquote>You can either put this in a let block inside the `main` function, or you can make it it's own thing.</blockquote> It should be <i>its own</i> instead of <i>it's own</i>. |
| json metadata | {"app":"steemit"} |
| Transaction Info | Block #25871591/Trx 3cc5b1d86d92c55106084cdce80d1fe8a169ba2d |
View Raw JSON Data
{
"trx_id": "3cc5b1d86d92c55106084cdce80d1fe8a169ba2d",
"block": 25871591,
"trx_in_block": 17,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:52:09",
"op": [
"comment",
{
"parent_author": "aas-sh",
"parent_permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"author": "grammarnazi",
"permlink": "re-aas-sh-an-introduction-to-developing-games-in-haskell-with-apecs-20180911t165202237z",
"title": "Minor Correction",
"body": "You have a minor grammatical mistake in the following sentence: <blockquote>You can either put this in a let block inside the `main` function, or you can make it it's own thing.</blockquote> It should be <i>its own</i> instead of <i>it's own</i>.",
"json_metadata": "{\"app\":\"steemit\"}"
}
]
}aas-shpublished a new post: an-introduction-to-developing-games-in-haskell-with-apecs2018/09/11 16:52:06
aas-shpublished a new post: an-introduction-to-developing-games-in-haskell-with-apecs
2018/09/11 16:52:06
| parent author | |
| parent permlink | blog |
| author | aas-sh |
| permlink | an-introduction-to-developing-games-in-haskell-with-apecs |
| title | An Introduction to Developing games in Haskell with Apecs |
| body | > This post can be found on my blog [here](https://blog.aas.sh/posts/2018-09-10-Making-A-Game-With-Haskell-And-Apecs/). There have been so many frameworks, examples and prototypes released in an effort to pioneer games development in Haskell, and yet we still don't really have many (if any) commercial releases we can look to for inspiration. I want to help relax the entry point into Haskell game development and show people how much fun programming your game in Haskell can be. I used to make YouTube guides for video games and generally I got positive responses, and so I figured that I could do something similar here with my blog posts or even my YouTube channel. Working with Haskell in the games industry is a little bit of a pioneering job, but I'm a firm believer that our technology is advanced enough such that we should be able to sacrifice a little bit of performance to make development easier. [My first experience wasn't amazing](https://blog.aas.sh/posts/2018-06-09-Of-Boxes-And-Threads/), but after a bit of time working on other things and a lot of thinking I decided to try again. This time, rather than researching through doing everything myself, I figured I'd try a framework made by someone else. This guide has been written by myself, who is in-between the beginner and advanced stages of Haskell - I've read the [Haskell Book](http://haskellbook.com/) but I'm still learning as I apply my knowledge in practice. I'm hoping that my beginnerish perspective will help people who are less academically inclined as myself digest things easier, I simply want to create shortcuts for those people close behind! > Please note that while I'm not going to assume Haskell mastery I am expecting at least a little bit of Haskell or functional programming knowledge. I'm not going to go through the absolute basics, but I will walk through what I'm doing so that new Haskellers understand what's going on. I will also not talk about how to set up a project with Stack, I will purely be focusing on Haskell. ## Why Haskell for Games? You can make a game in pretty much any programming language, and whether you *should* is entirely up to you. However, there are many barricades that have got in the way of Haskell being used in games. I've been working on my Haskell game for about a Month now, and I wanted to really feel confident in the language before I started preaching that it's possible. It doesn't matter what framework you choose or whether you roll your own, the language itself is the bread and butter for your game and it has to be suited to the task. One reason people choose to avoid Haskell is simply the difficulty of the language itself. Games development is as hard as you decide it to be, with many different engines, frameworks and languages to choose from. While I agree that for most people it may be difficult to get their head around Haskell, once you have the foundations set up the process of adding additional mechanics will get easier as time goes on. I would like to take a moment to praise Apecs for how many problems it alleviates when using a functional language. I'm sure that the other frameworks out there will make Haskell comfy as well, and this is by no means an argument to use Apecs, it is simply a testament to its usability. Without going into massive detail on the ins and outs of Haskell and FP languages, Haskell paired with Apecs really does make development a whole lot easier, and I can really envision a future where people may choose languages like Haskell to simplify development. * 9/10 times, if it compiles, your game will run. Maybe not as expected, but at least it won't crash! * Using [Stack](https://docs.haskellstack.org/en/stable/README/) and [Stackage](https://www.stackage.org/), all of the dependencies for your game are downloaded automatically by simply listing them, making it easy to build your projects. * [GHCJS](https://github.com/ghcjs/ghcjs) allows you to compile your Haskell code to Javascript if you wanted to make a web game or something similar * Haskell's type system ensures that you know the difference between pure and impure functions. By organising code in this way, you streamline your game's structure making it *extremely easy* to find logical errors in your game. * Important functions for *doing* things can be wrapped up in monads and take advantage of `do` syntax, meaning that you can execute multiple side effects * Functions are first class citizens, they are treated in the exact same way as values and can be stored just as easily (hooray for spell making!) * People say learning and using Haskell will help you even in imperative languages. I like Haskell because it makes me feel good when I solve something, so if you enjoy Haskell then why not make a game in a language you enjoy? Without further ado, let's start making a game! ## Getting Started ### Initialising For this project, we will start off with [Apecs](https://hackage.haskell.org/package/apecs) and [SDL2](https://hackage.haskell.org/package/sdl2). Choose whatever suits you, but I will be showing off a fair bit of Apecs and I will be starting the project with SDL2, so you'll have to research how to start your game off independently. I will also be using [SDL-ttf](https://hackage.haskell.org/package/SDL-ttf) and [SDL-image](https://hackage.haskell.org/package/SDL-image), remember, if you are also using packages that have bindings to C you will also need to install them onto your system, not just the Haskell bindings. Now, let's show some code. > Note that I am importing SDL with `qualified`, so that every SDL function has SDL before it. I mainly do this in the main file as there's a lot going on. Do as you wish. Also, this won't compile yet due to us not having the `initialise` function implemented. ```hs import Apecs import qualified SDL import qualified SDL.Image(quit) import qualified SDL.Font -- Uses templateHaskell to create the data 'World' -- also creates initWorld makeWorld "World" [] main :: IO () main = do -- Initialise Apecs world world <- initWorld -- Initialise SDL SDL.initialize [SDL.InitVideo] SDL.Font.initialize -- Create a window and renderer window <- SDL.createWindow "App" SDL.defaultWindow renderer <- SDL.createRenderer window (-1) SDL.RendererConfig { SDL.rendererType = SDL.AcceleratedRenderer , SDL.rendererTargetTexture = False } -- Do any initialisation here! runSystem initialise world -- Display the game SDL.showWindow window -- Insert loop code here! -- Delay shutdown if you like? SDL.delay 1000 SDL.destroyRenderer renderer SDL.destroyWindow window SDL.Image.quit SDL.Font.quit SDL.quit putStrLn "Goodbye!" exitSuccess ``` Okay, so here we have a basic main function that creates a world and then closes it. Nothing special. I even threw in [SDL.Delay](https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Time.html#v:delay) so you can see the window before it closes. Note that `SDL.Image` is initialised when used unlike the core and font variations, which is why only quit is imported here. This code isn't anything special so I should probably stop typing and move on to describing a simple game loop. But first, let's look at [Apecs' `makeWorld` function](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:makeWorld). If you actually clicked the link above you would have noticed that it says "turns into" at some point. This function uses Template Haskell, and simply writes a lot of things for you. The reason that you will never find the `World` type is that it is actually created in the `makeWorld` function described, and so the function `initWorld` is specialised to the type created in `makeWorld`. The function `makeWorld` accepts a string which will become the type (in our case, "World" becomes `World`) along with a list of components we are yet to make. To sum it up, `makeWorld` is simply a template that creates the world type and a bunch of functions for said world for you which your entire game will revolve around. ### Loop function Now for the loop function: ```hs let loop prevTicks secondTick fpsAcc prevFps = do ticks <- SDL.ticks payload <- map SDL.eventPayload <$> SDL.pollEvents let quit = SDL.QuitEvent `elem` payload dt = ticks - prevTicks calcFps = secondTick + dt > 1000 newFps = if calcFps then fpsAcc + 1 else prevFps newFpsAcc = if calcFps then 1 else fpsAcc + 1 newSecondTick = if calcFps then mod (secondTick + dt) 1000 else secondTick + dt -- React to input runSystem (handlePayload payload) world -- Update the world runSystem (step $ fromIntegral dt) world -- Set the background colour and clear the screen SDL.rendererDrawColor renderer $= V4 0 0 0 0 SDL.clear renderer -- Render the world join $ runSystem (draw renderer newFps) world SDL.present renderer unless quit $ loop ticks newSecondTick newFpsAcc newFps -- Begin looping loop 0 0 0 0 ``` You can either put this in a let block inside the `main` function, or you can make it it's own thing. Up to you. What matters is that you understand that we are recursively looping almost indefinitely until the user closes the window (ie, giving SDL the `QuitEvent`). Don't worry if there's a lot of stuff you don't understand, take a moment and research the functions presented to you. I could probably have named the variables better, but I've essentially made a simple FPS counter for this tutorial. Yes, it could probably be better and yes, there's probably [something like this](https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Framerate.html) that does it for you. I just wanted to illustrate how ticks and time work here. ### Ticks There are 1000 ticks in a second (1 tick is 1 millisecond), and the `ticks` function allows us to see how many ticks have passed since SDL was initialised. We can use this to work out the time since the previous frame (`dt` or [*delta time*](https://en.wikipedia.org/wiki/Delta_timing)). Here, I am using `secondTick` to time seconds, and so `calcFPS` is `True` when a second has passed. The `newFPS` value will either display the fps for the previous second (`prevFps`), or it will display the current running total + 1 stored in `fpsAcc`. Finally, the timer tracking seconds is reset. It's a bit ugly, but this a very easy and primitive way of tracking FPS in the early days, not that we are rendering any text yet. Let's start getting into the basics of Apecs. ## Apecs Components ### Remembering Types Okay, so there are a couple of lines that won't compile as we haven't implemented them yet. Let me take the time to explain the role of ['runSystem'](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:runSystem). In Apecs, `System` is a monad that most of your code will produce at some point. I'm not going to talk about what a monad really is as that's a hot topic, but I can show what they can do. To put it simply, `runSystem` ***does*** something. It can or *will* execute side effects and can produce multiple side effects at once. The `System` monad is how you will manipulate your game. Here's a refresher on [creating types in Haskell](https://wiki.haskell.org/Constructor). We will need all of these if we're going to get anywhere with Haskell. * **`type`:** A *type synonym*. You can replace the occurence of your type with what it represents, it does nothing else. Functions can accept types in addition to what the type represents, it's just an alias. Example: ```hs type String = [Char] type LongThing = (Int, Int, Int, Int, Int) ``` * **`data`:** A *type constructor*. You can craft your own types out of other types (think classes or structs in other languages). Functions that take or return your type will not accept anything but your type, and you will have to deconstruct it to access the contents. Example: ```hs data Bool = True | False data Maybe a = Just a | Nothing data Action = MoveTo (V2 Int) | Attack Entity | Cast Spell | Wait Int ``` * **`newtype`:** A *type constructor* that acts as a wrapper for a single type. Your type will act just like it would if you used `data`, but is more efficient. If you are simply wrapping your type around something, use this. Example: ```hs newtype PositionComponent = PositionComponent (V2 Double) ``` ### Creating Components Now, let's create some simple components to manipulate. Examine the code below in addition to modifying our `makeWorld` call. Note that `V2` is contained within `SDL.Vect`, which re-exports the package [`Linear`](https://hackage.haskell.org/package/linear) (ie, if you are using SDL, you do not need to install `Linear` as it comes with it. `Linear` comes with lots of nice types like `V2`, `V3` and `V4`, go take a look.) ```hs -- Global component, exists outside of entities -- Used for managing the passage of time newtype Time = Time Double deriving Show instance Semigroup Time where (<>) = mappend instance Monoid Time where mempty = Time 0 instance Component Time where type Storage Time = Global Time -- Unique component, either one or none exists data Player = Player deriving Show instance Component Player where type Storage Player = Unique Player -- Position of game entities newtype Position = Position (V2 Double) deriving Show instance Component Position where type Storage Position = Map Position -- Name of game entities newtype Name = Name String deriving Show instance Component Name where type Storage Name = Map Name -- Uses template Haskell to create the data 'World' -- also creates initWorld makeWorld "World" [''Time, ''Player, ''Position, ''Name] ``` So here we have three components. The first, `Time`, is a `Global` component. This means that there's ***only one of it at any one time, and it belongs to no entity***. This is appropriate as time is, well, global. Although, it does actually belong to an entity secretly - an entity in Apecs (and many other implementations) is just an integer to reference components together. Global components are stored on entity *-2*, which will never be interfered with with normal usage of apecs. Time is a newtype - we would have liked to use just a `Double`, but because we need to provide our own instances of typeclasses, we need to `newtype` it as type synonyms don't have their own implementations. We implement the `Component` typeclass so that apecs knows what kind of component it is. You can see the different kinds of entities [here](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Stores.html). It also needs to implement instances of `Semigroup` (usually you can just specify `mappend`, it's worked for me this far!), and `Monoid` (specify what an 'empty' component looks like, as this is the initial state of the component as it exists from the beginning of the game). Second, we have the `Player` component. This type has only one data constructor, `Player`. The purpose of this component is to simply mark which entity is the player - ***there can only be unique entity at once, giving it to a new entity removes it from the previous***. Nothing much else to say about this for now, but it will come into play later. Finally, we have `Position`. Again, this is a newtype so that we can create instances of `Component` - *every component in Apecs needs this instance, so try to provide these to prevent [Orphan Instances](https://wiki.haskell.org/Orphan_instance).* Even though that the implementation of `V2` is the following.. ```hs data V2 a = V2 a a ``` .. It is still a single piece of data in the same way that `(a,b)` is also a single piece of data (a tuple containing two fields of possibly different types). As a final note, notice how `makeWorld` now contains components. This piece of template Haskell is going to take what we've done and allow our component types to be used within the Apecs `World`. This means that everything found in [Apecs.System](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-System.html) will now be compatible with your types. Okay, so maybe that was a tough section, maybe it wasn't. Maybe you're learning something or maybe you're upset that I've done something in a beginnerish way. Either way, this code should be close to compilation and should be enough to demonstrate some basics of Apecs. ## Systems ### Side Effects in Monads In an [Entity Component System](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system) such as Apecs, *systems* are what make the world go round. Normally in C++ or C#, I'd make my ECS seperate from a few things baked into the engine, but with Apecs I have to imagine a lot of things as a global component instead. The game's map, texture caches and other assets will most likely manifest as a global component here, if you wouldn't already have implemented things in this way. Up to this point in the tutorial, I've given code examples that haven't given much room for flexibility and I assume that you've been following along with me. For this area though, I'm going derail a little bit and just try to show off what apecs can do. I'll provide usable, relevant code, but obviously what you choose to do depends on your game. This section is going to be fairly lengthy and have a lot of code, but if you follow along and understand the methodology I'm sure that you can apply what I give to your own code. Firstly, some usage. Apecs has a function that I've touched on already called ['runSystem'](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:runSystem). This function will execute side effects contained within the monad and therefore strip away the `System` part. Here's an example of how this may look with the IO monad: ```hs main :: IO () main = do -- The following will be executed just like how -- runSystem would execute one of your systems putStrLn "Here's a basic print function!" -- The following will NOT be run.. let funcThatProducesIOIO = pure $ putStrLn "Here's an IO(IO())!" foo <- funcThatProducesIOIO -- ..until it is called like so foo -- That was because 'foo' has type IO (), but this -- is simply the storage of the monad, not execution -- pure wraps the argument inside the monad, leading to -- IO (IO ()), which when bound to foo, creates type IO () -- This means that one layer of IO has been executed but -- not the second. -- This pattern is dumb, binding something just to call it. -- This will work instead: join funcThatProducesIOIO ``` Hopefully that code above makes some sense. Because the main thread will execute IO in order to actually make something happen with the program, anything that has type `IO ()` will be executed automatically. The final example was something I wanted to mention because of some confusion with monads that a few people have asked me. When we bind something using `<-`, the monad on the right is executed to produce the thing inside it. `IO (String)` would produce a `String`, for instance (this could be reading in from the keyboard?). This means that if the thing produced is yet another monad, like IO (), the thing on the left is not executed, and `join` is a nice shortcut to save you binding and executing as demonstrated above. Why am I telling you this? Because no matter whether you use SDL or not, you will want to perform IO to make things appear on screen. If you have a system which produces IO, like a render system, then you will need to use `join` in order to execute the side effects contained within the monad you retrieved. ### Easy System Type Synonym Next up, a simple type synonym. The following will make using Apecs a lot easier: ```hs -- Easy type synonym for systems type System' a = System World a ``` Remember, this is a type synonym, it doesn't actually affect your code in any way. It simply saves you from typing and keeps reading type signatures easier. All `System World a` means is that, assuming your world from your `makeWorld` function was named ``"World"``, that this system operates within your world and can make a change in some way. ### Writing the Initialisation System If we scroll up to our initialisation code, you will see we do: ```hs -- Do any initialisation here! runSystem initialise world ``` It is now time to write our `initialise` system. This system is simply going to act as our kickstart to the game, add our player, do things. I'm sure you can guess what your game will need to do to set things up. One final thing I need to mention is that [a System has the following type](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Core.html#t:SystemT): `newtype SystemT w m a `. This may not mean anything at first, but the documentation clearly states that the monad `m` used in a system is in fact compatible with IO. Anything to do with IO can be performed as a part of a system, which may help with debugging. Lets go! Here's a sample initialisation system: ```hs -- The type of this function is System' (), so when we open up -- a 'do' block, we are allowing us to bind the contents of System' monads -- as well as executing side effects of any other System' () easily. initialise :: System' () initialise = do -- Make sure you use liftIO to get the following to compile, -- we are returning System' (), not IO (), hence the lift. -- Lift is used to lift a function producing a -- monad of one type (IO) into another (System'()). liftIO $ putStrLn "Let's do some IO just to prove we can!" -- Let's initialise the time monad, even though we don't -- really have to as Apecs handles that for us. -- 'set' produces a System' (), which means this line -- will be executed as part of this system. set global $ Time 0 -- Another two System' ()s, this time we're creating entities newEntity (Player, Name "Lola", Position $ V2 0 0) newEntity (Name "Harold", Position $ V2 0 0) ``` Remember, we're looking at the functions [on the Apecs Hackage docs](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-System.html) for all of our inspiration on what functions to use. It is pretty self explanatory when you get the hang of it I promise. Make sure you're looking at the most up to date version of all your documentation. Honestly, if you understand how these all work, how we compose monads to execute side effects and how Apecs allows us to run these System's from the main thread to play our game, things will get much easier. If not, fear not, you'll get there. Hopefully some more examples will help. ### Writing the Step System Recall that we call the following during our main game loop: ```hs -- Update the world runSystem (step $ fromIntegral dt) world ``` This is our second system. This will be more important than the previous, with this being a collection of every system you require execution of each frame. Notice how we are calling this `runSystem` - the system we pass to it has some extra parameters inside. When that parameter is evaluated, `step` will accept `dt` and evaluate into a `System' ()` as you'd expect of any programming language in the same way that passing `(1 + 1)` would be equivalent to an `Int`, as the function: ```hs (+) :: Num a => a -> a -> a ``` has been fully evaluated. This means that our new system looks similar to the following: ```hs -- Okay, so we have access to delta time now. -- This allows us to animate or simulate stuff. -- Notice how we can execute other systems inside -- this system with no problems. step :: Double -> System' () step dT = do moveCharacters dT rootPlayer -- The function cmap below finds every entity with a Position -- and rewrites it with new values - adding dT to the x and y values. -- 'cmap' is another function producing System' () moveCharacters :: Double -> System' () moveCharacters dT = cmap (\(Position (V2 x y)) -> Position $ V2 (x + dT) (y + dT)) -- Apecs has a lot of magic involved, look at this: rootPlayer :: Double -> System' () cmap (\(Player, Position _) -> Position $ V2 0 0) -- This iterates on all entities with both a Player component and -- Position component, however, Player is unique, so this is only -- applied to the player. -- This is actually a bit dumb, as we're operating on the player twice, -- so let's rewrite that first call: -- Not is an Apecs Data Constructor used for the exclusion of a component. -- We have to specify the type of Not as GHC cannot infer this on its own. -- This will operate on entities without a Player component. moveNonPlayerCharacters :: Double -> System' () moveNonPlayerCharacters dT = do cmap (\(Position (V2 x y), Not :: Not Player) -> Position $ V2 (x + dT) (y + dT)) ``` ### Apecs Magic with Systems In the above examples, the function `cmap` allowed us to read components and overwrite them. There's a lot more to it, and once you get used to the different approaches you'll have to commend Apecs for the amount of work put into it. Any of the functions in the Apecs documentation that take or write `Components` (or `c`, as the documentation uses types and magic to make things polymorphic) can take a variety of different forms. As you saw above, you can read multiple components as we did with `(Player, Position _)` (note that in that case we used `_` to ignore the parameter, as we were overwriting the position). You can actually write to multiple components too! As long as the components are produced as a tuple, just like the example just given, then you can return multiple components too. Not that ignoring any input components will leave them alone - we didn't need to write `Player` again to preserve it on the entity. I'm going to just throw some examples that I can think of at you now. I'll talk about what they do after each segment. I'm going to be calling functions and using Components that we haven't defined, the idea being that these are just to demonstrate different methods of using Apecs. ```hs everyoneChasePlayer :: System' () everyoneChasePlayer = do [(Player, Position p)] <- getAll cmap (\(Position p', Not :: Not Player) -> Position $ moveTowards p' p) ``` Here, using `do` syntax, we can get components attached to the `player` very easily. When there's only one element in the list we can pattern match on it just like a tuple, but this may crash your program if the `Player` does not exist or if you don't grab a unique component and therefore have more than one entity. By grabbing the player's position, we can pass that to a function called `moveTowards` which is in charge of manipulating the first argument so that it gets closer to the second. This function is pure, as `cmap` is the function producing the `System' ()` monad, so you can forget about Apecs and focus on your logic when writing it. ```hs debugCharacters :: System' () debugCharacters = cmapM_ (\(Name n, Entity e) -> liftIO $ putStrLn ("Entity " ++ show e ++ " is named: " ++ n)) ``` Here's a simple template you can use for debugging. As previously mentioned, `System' ()` supports `MonadIO`, allowing you to perform `IO` inside it. `cmapM` allows us to read components and iterate over them monadically (basically we can treat each iteration as another `System' ()`), which allows us to perform side effects instead of being locked into a pure environment like with the previous example. If we used `do` here, we could even call another system too! Also, notice how we found the `Entity` here - whenever we use `getAll` or `cmap` or anything that gets components (other than `get`), we can allocate bindings for the `Entity` these components belong to. `Entity` is just a newtype for `Int`, so `e :: Int` in this case, hence why we `show` it. The `n` is simply a string which doesn't require the use of `show`. If we want to actually use the `Entity`, be sure to wrap the `Int` back in an `Entity` or simply grab the entity as `e :: Entity` rather than pattern matching as we did here. Finally, the `cmapM_` function (notice the `_`) that we used is the same as `cmapM`, but it doesn't write anything. It's job is to read and provide the a way of monadically iterating. If we wanted to change the name of the entity, using `cmapM` instead would allow us to return something out of the monadic iteration to write the entity with. Here's an example of writing components with `cmapM`: ```hs applyGravity :: Double -> System' ()] applyGravity dT = cmapM (\(Position (V2 x y), e :: Entity) -> do let gY = y + (dT * 0.5) y' = max gY 0 liftIO $ putStrLn ("Entity " ++ show e ++ " moved from " ++ show y ++ " to " ++ show y') pure $ Position (V2 x y')) ``` So here we have an example of using `let` to make calculations easier, along with some `IO`, getting the `Entity` and finally overwriting `Position` components to apply gravity (in SDL and many other frameworks, the top left is `(0,0)`, so positive `y` moves things down). ```hs fireWeapon :: V2 Double -> Double -> System' () fireWeapon (V2 i j) -> speed = do [(Player, p :: Position, Weapon ammo, e :: Entity)] <- getAll when (ammo > 0) $ void $ do let ammoLeft = max 0 $ ammo - 1 set e (Weapon ammoLeft) newEntity (Velocity (i * speed) (j * speed), p) ``` Here's an example of making a new entity while producing `System' ()`. When the side effects of this system are performed, we begin by grabbing the `Entity` with the `Player` component along with some other components. Remember, we need to make sure beforehand the player has these components otherwise the pattern matching will fail, and we can only pattern match here because we know we are only going to have one element in this list. We then set the `Weapon` component on the player to a new value. The function `set` can be used regardless of if it already exists on the entity or not, and so can be a better option than `cmap`. Additionally, `set` requires you to provide the entity you're modifying, meaning that if we weren't operating on a unique entity then `cmap` wouldn't be as good - `cmap` iterates over ***every*** entity with the matching components. You have more control with `set`, just make sure that you're not wasting your time when you could use `cmap` or any other Apecs function. Lastly, notice our use of `when` and `void`. The function `when` is exported by `Control.Monad`, and is pretty much equivalent to the following: ```hs when' :: Bool -> m () -> m () when bool func = if bool then func else pure () ``` Basically, `when` will do ***nothing*** when it's logic is false. There's the reverse of when too, called `unless`. The other function, `void` will execute execute the side effects of the monad passed to it, but discard the value returned. When we use `newEntity` to create a new Entity, the Entity created is returned as `System' (Entity)`. Since we want this function to return a blank `System' ()`, we need to just ignore what is returned (don't worry, the entity is not deleted) so that the whole thing type checks. ### Writing the Event Handler System Okay, this section is going to start combining SDL code with Apecs. There are plenty of guides on how to use SDL, so I'm going to show the code first and mention anything important after. Remember that SDL gives you a list of all the events that have occurred since the last poll and you need to handle them all individually. I have not yet implemented any code to check for modifier keys like `shift` or `ctrl`. This will use many of the techniques shown in the previous section so hopefully you can follow along easily. ```hs -- Global component used for changing gamestates data GameMode = Standard | Look deriving (Show, Eq) data GameState = Game GameMode | Interface deriving (Show, Eq) instance Semigroup GameState where (<>) = mappend instance Monoid GameState where mempty = Game Standard instance Component GameState where type Storage GameState = Global GameState -- Handle the entire event payload handlePayload :: [EventPayload] -> System' () handlePayload = mapM_ handleEvent -- The main event handler function for dealing with keypresses handleEvent :: EventPayload -> System' () handleEvent (KeyboardEvent ev) = handleKeyEvent ev handleEvent _ = pure () -- For the handling keyboard events only handleKeyEvent :: KeyboardEventData -> System' () handleKeyEvent ev = do (state :: GameState) <- get global let code = keysymKeycode $ keyboardEventKeysym ev case keyboardEventKeyMotion ev of Pressed -> case state of Game mode -> gameAction mode code Interface -> postMessage "Interface state not implemented yet" Released -> pure () -- For keyboard events that take place in the game gameAction :: GameMode -> Keycode -> System' () gameAction mode k = let intents = lookup k defaultGameIntents in case mode of Standard -> case intents of Just (Navigate dir) -> navigate dir Just ToggleLook -> toggleLook mode Just Wait -> do postMessage "You wait.." playerActionStep 100 _ -> pure () Look -> case intents of Just (Navigate dir) -> moveReticule dir Just ToggleLook -> toggleLook mode _ -> pure () -- Initial bindings for intents defaultGameIntents :: [(Keycode, GameIntent)] defaultGameIntents = [ (KeycodeUp , Navigate C.Up) , (KeycodeLeft , Navigate C.Left) , (KeycodeDown , Navigate C.Down) , (KeycodeRight , Navigate C.Right) , (KeycodeSemicolon, ToggleLook) , (KeycodeW, Wait) ] ``` I first have created a component called `GameState`, maybe that's not the best name. This `Global` component is basically going to help us work out the context of what's on screen. For instance, our inputs on the arrow keys may move the player in game, but on a menu it will do something else. I haven't done any of the interface stuff yet, but I have two different modes for the actual game. I'm making an Roguelike RPG, and one requirement is that the player can look at things without moving and interacting with anything. This component allows me to firstly see whether we're in game or not and secondly, if we are in game, what we are doing. These things are very likely to change to suit whatever game you're making, but I'm hoping for the purposes of this tutorial you can see what I'm getting at. The `handlePayload` function itself starts by taking the entire payload and performing `mapM_` on it - `mapM_` is not an Apecs function but rather one that is found in `Control.Monad`. If you were following what the `cmapM_` function did earlier, this might already be clear. This function is very similar except that instead of iterating over Apecs components, it iterates over whatever `Traversable` class you pass it, in this case, a list. We are using the `mapM_` version of map because a normal `map` function doesn't give us the monadic context we need to do this cleanly, whereas `mapM_` allows us to produce a `System' ()` for each element of the list, and the `_` simply discards any data that isn't a side effect, as we aren't using anything. This takes us into the `handleEvent` function, which now only has to worry about a single `SDL.Event`. The `handleEvent` system I've written does simple pattern matching on the type of event it is given. If the event is a `KeyboardEvent`, it is opened up to expose the event itself and is then passed on to `handleKeyEvent`. I haven't thought about other `SDL.Event`s yet, as our main loop already handles checking for the `QuitEvent`, which means everything I deem important has been handled. Maybe you want something to happen when the screen is resized or if the mouse is clicked, you should go and check out [the docs](https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Event.html#t:EventPayload) to find what kind of events you might need, and what data those events contain. Our `handleKeyEvent`'s job is to direct the flow of the program to where it needs to go next. This is now getting to the point where different games will do different things. My game isn't interested in any key releases, so if the type of `keyboardEventKeyMotion ev` matches `Released` I don't do anything. Otherwise, I call my own function, `gameAction` along with the current mode and the keycode. Remember that anywhere inside any of these functions you can call as many `System' ()` functions as you like to compose the monad. Apecs has allowed us to keep our code clean and healthy while also giving us room to do whatever we like as long as we construct `System' ()` as the output, which as we know, is really easy when you know how. ### Writing the Draw System Recall that the draw system interacts with the `IO` monad. I've shown already how you can use `liftIO` to execute `IO` from within a `System' ()`, but I've also shown how returning `System (IO ())` can also be used to draw when the `join` function (found in `Control.Monad`) is used. You should have enough information to get a basic drawing system going. One of the hardest challenges you'll face early on is managing your textures, fonts and other assets. It's easy to create a `Texture` component and give each `Entity` the texture it's going to render with, however, this means that having five entities that show the same thing will have the same texture loaded five times over. I've created `Global` components for `Textures` and `Fonts` which implement `HashMap`s (found in `Data.HashMap`). A `HashMap` is like a normal map but it runs a lot faster as it isn't ordered. My `draw` system then passes the assets found inside these components to whatever functions need them. You can of course, just use `IO` in the main loop and pass everything to the `draw` system to avoid loading things multiple times, but this would mean having all of your assets loaded at once. Eventually, I plan on scanning all of my `Sprite` components and loading / unloading assets inside the hashmap depending on what textures are required. Here's the current code: ```hs -- Turns a list of key value pairs into a hashmap for a resource component createResourceMap :: [(String, a)] -> HM.Map String a createResourceMap = foldl (\m (k, v) -> insert k v m) empty -- Types for creating textures type TexResource = (String, Texture) type TextureMap = HM.Map String Texture -- Create a TextureMap with initial filepaths loadTextures :: Renderer -> [FilePath] -> IO [TexResource] loadTextures r = traverse getTex where getTex p = do tex <- loadTexture r p pure (p, tex) -- Types for creating fonts type FontResource = (String, Font) type FontMap = HM.Map String Font -- Create a FontMap using initial filepaths loadFonts :: [(FilePath, PointSize)] -> IO [FontResource] loadFonts = traverse getFont where getFont (p, s) = do font <- load p s pure (p, font) -- Global store of all textures newtype Textures = Textures TextureMap instance Component Textures where type Storage Textures = Global Textures instance Semigroup Textures where (<>) = mappend instance Monoid Textures where mempty = Textures HM.empty -- Global store of all fonts newtype Fonts = Fonts FontMap instance Component Fonts where type Storage Fonts = Global Fonts instance Semigroup Fonts where (<>) = mappend instance Monoid Fonts where mempty = Fonts HM.empty -- Create System' (IO ()) for everything depending on item drawn draw :: SDL.Renderer -> Int -> System' (IO ()) draw renderer fps = do Textures texs <- get global Fonts fonts <- get global let uiFont = HM.lookup "Assets/Roboto-Regular.ttf" fonts sequence_ <$> sequence [ drawComponents $ renderSprite renderer texs , drawComponents $ renderReticule renderer , displayFps renderer fps uiFont ] -- Produce a system used for drawing drawComponents :: Get World c => (c -> Position -> IO ()) -> System' (IO ()) drawComponents f = cfold (\img (p, comp) -> img <> f comp p) mempty -- Render textures renderSprite :: SDL.Renderer -> TextureMap -> Sprite -> Position -> IO () renderSprite r ts (Sprite fp rect) (Position p) = case HM.lookup fp ts of Just tex -> SDL.copyEx r tex (Just $ toCIntRect rect) (Just (SDL.Rectangle (P $ toCIntV2 p) tileSize')) 0 Nothing (V2 False False) _ -> pure () -- Render the target reticule renderReticule :: SDL.Renderer -> Reticule -> Position -> IO () renderReticule r (Reticule on) (Position p) | not on = pure () | on = do rendererDrawColor r $= V4 255 255 255 20 fillRect r $ Just $ Rectangle (P $ toCIntV2 p) tileSize' -- Display FPS displayFps :: SDL.Renderer -> Int -> Maybe SDL.Font.Font -> System' (IO ()) displayFps r fps Nothing = pure $ pure () displayFps r fps (Just f) = pure $ renderSolidText r f (V4 255 255 255 255) ("FPS: " ++ show fps) (V2 0 0) False -- Render solid text renderSolidText :: SDL.Renderer -> SDL.Font.Font -> SDL.Font.Color -> String -> V2 Double -> Bool -> IO () renderSolidText r fo c s p = renderText r fo (SDL.Font.solid fo) c s (toCIntV2 p) -- Render text to the screen easily -- renderSolidText calls this renderText :: SDL.Renderer -> SDL.Font.Font -> (SDL.Font.Color -> Data.Text.Text -> IO SDL.Surface) -> SDL.Font.Color -> String -> V2 CInt -> Bool -> IO () renderText r fo fu c t (V2 x y) center = do let text = Data.Text.pack t surface <- fu c text texture <- SDL.createTextureFromSurface r surface SDL.freeSurface surface fontSize <- SDL.Font.size fo text let (w, h) = (fromIntegral *** fromIntegral) fontSize unless center $ SDL.copy r texture Nothing (Just (Rectangle (P $ V2 x y) (V2 w h))) when center $ do let x' = x - fromIntegral (fst fontSize `div` 2) SDL.copy r texture Nothing (Just (Rectangle (P $ V2 x' y) (V2 w h))) SDL.destroyTexture texture ``` > This code is just a rough draft just so that I can see things on screen. While I recommend beginners using this so that they can start having fun with Haskell, I ***deeply encourage*** you to make optimisations wherever you can and tailor everything to your game. The `renderText` function is severely inefficient and so I'm going to be trying to batch all of the text onto one surface before creating a texture out of it. This code is ***not good***. Oh my gosh, what a lot of code. I'm sorry for just dumping so much, but at the same time there's no better way to illustrate how I try to do things. This might be pretty complex and hard to read for the beginners reading this, but all I can say is that you should begin by looking at the function types for each block of code and understanding how the functions use each other. Most importantly, see how we go from producing `IO ()` in `renderText` and `renderSolidText` to producing `System' (IO ())` when bundled with `displayFPS` or `drawComponents`. The `drawComponents` function simply uses `cfold` to combine all of the `IO ()` monads into one, before wrapping `System' ()` around it like all the other Apecs functions do. ## Conclusion I'm sorry for the huge amount of code pastes, but hopefully there's at least something written in this blog post that will teach someone something. My real intent is to encourage the usage of Haskell for the creation of small games where we no longer need performance as much as we used to. Hopefully this inspires of more programmers and more frameworks to use Haskell so that writing in a functional language becomes less of an alien idea. I want to see indie developers start embracing the power of high-level languages to make development easier on their already-difficult lives. If people can make [cool games in JavaScript](https://store.steampowered.com/app/497800/Golden_Krone_Hotel/), then why not Haskell? |
| json metadata | {"tags":["blog","programming","haskell","guide","games"],"links":["https://blog.aas.sh/posts/2018-09-10-Making-A-Game-With-Haskell-And-Apecs/","https://blog.aas.sh/posts/2018-06-09-Of-Boxes-And-Threads/","http://haskellbook.com/","https://docs.haskellstack.org/en/stable/README/","https://www.stackage.org/","https://github.com/ghcjs/ghcjs","https://hackage.haskell.org/package/apecs","https://hackage.haskell.org/package/sdl2","https://hackage.haskell.org/package/SDL-ttf","https://hackage.haskell.org/package/SDL-image","https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Time.html#v:delay","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:makeWorld","https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Framerate.html","https://en.wikipedia.org/wiki/Delta_timing","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:runSystem","https://wiki.haskell.org/Constructor","https://hackage.haskell.org/package/linear","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Stores.html","https://wiki.haskell.org/Orphan_instance","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-System.html","https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system","https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Core.html#t:SystemT","https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Event.html#t:EventPayload","https://store.steampowered.com/app/497800/Golden_Krone_Hotel/"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25871590/Trx aa2bc2cbdccc7db8e3ecc4f87268e53231ef9e6b |
View Raw JSON Data
{
"trx_id": "aa2bc2cbdccc7db8e3ecc4f87268e53231ef9e6b",
"block": 25871590,
"trx_in_block": 34,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-09-11T16:52:06",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "blog",
"author": "aas-sh",
"permlink": "an-introduction-to-developing-games-in-haskell-with-apecs",
"title": "An Introduction to Developing games in Haskell with Apecs",
"body": "> This post can be found on my blog [here](https://blog.aas.sh/posts/2018-09-10-Making-A-Game-With-Haskell-And-Apecs/).\n\nThere have been so many frameworks, examples and prototypes released in an effort to pioneer games development in Haskell, and yet we still don't really have many (if any) commercial releases we can look to for inspiration. I want to help relax the entry point into Haskell game development and show people how much fun programming your game in Haskell can be. I used to make YouTube guides for video games and generally I got positive responses, and so I figured that I could do something similar here with my blog posts or even my YouTube channel.\n\nWorking with Haskell in the games industry is a little bit of a pioneering job, but I'm a firm believer that our technology is advanced enough such that we should be able to sacrifice a little bit of performance to make development easier. [My first experience wasn't amazing](https://blog.aas.sh/posts/2018-06-09-Of-Boxes-And-Threads/), but after a bit of time working on other things and a lot of thinking I decided to try again. This time, rather than researching through doing everything myself, I figured I'd try a framework made by someone else.\n\nThis guide has been written by myself, who is in-between the beginner and advanced stages of Haskell - I've read the [Haskell Book](http://haskellbook.com/) but I'm still learning as I apply my knowledge in practice. I'm hoping that my beginnerish perspective will help people who are less academically inclined as myself digest things easier, I simply want to create shortcuts for those people close behind!\n\n> Please note that while I'm not going to assume Haskell mastery I am expecting at least a little bit of Haskell or functional programming knowledge. I'm not going to go through the absolute basics, but I will walk through what I'm doing so that new Haskellers understand what's going on. I will also not talk about how to set up a project with Stack, I will purely be focusing on Haskell.\n\n## Why Haskell for Games?\nYou can make a game in pretty much any programming language, and whether you *should* is entirely up to you. However, there are many barricades that have got in the way of Haskell being used in games. I've been working on my Haskell game for about a Month now, and I wanted to really feel confident in the language before I started preaching that it's possible. It doesn't matter what framework you choose or whether you roll your own, the language itself is the bread and butter for your game and it has to be suited to the task.\n\nOne reason people choose to avoid Haskell is simply the difficulty of the language itself. Games development is as hard as you decide it to be, with many different engines, frameworks and languages to choose from. While I agree that for most people it may be difficult to get their head around Haskell, once you have the foundations set up the process of adding additional mechanics will get easier as time goes on.\n\nI would like to take a moment to praise Apecs for how many problems it alleviates when using a functional language. I'm sure that the other frameworks out there will make Haskell comfy as well, and this is by no means an argument to use Apecs, it is simply a testament to its usability. Without going into massive detail on the ins and outs of Haskell and FP languages, Haskell paired with Apecs really does make development a whole lot easier, and I can really envision a future where people may choose languages like Haskell to simplify development.\n\n* 9/10 times, if it compiles, your game will run. Maybe not as expected, but at least it won't crash!\n* Using [Stack](https://docs.haskellstack.org/en/stable/README/) and [Stackage](https://www.stackage.org/), all of the dependencies for your game are downloaded automatically by simply listing them, making it easy to build your projects.\n* [GHCJS](https://github.com/ghcjs/ghcjs) allows you to compile your Haskell code to Javascript if you wanted to make a web game or something similar\n* Haskell's type system ensures that you know the difference between pure and impure functions. By organising code in this way, you streamline your game's structure making it *extremely easy* to find logical errors in your game.\n* Important functions for *doing* things can be wrapped up in monads and take advantage of `do` syntax, meaning that you can execute multiple side effects\n* Functions are first class citizens, they are treated in the exact same way as values and can be stored just as easily (hooray for spell making!)\n* People say learning and using Haskell will help you even in imperative languages. I like Haskell because it makes me feel good when I solve something, so if you enjoy Haskell then why not make a game in a language you enjoy?\n\nWithout further ado, let's start making a game!\n\n## Getting Started\n\n### Initialising\nFor this project, we will start off with [Apecs](https://hackage.haskell.org/package/apecs) and [SDL2](https://hackage.haskell.org/package/sdl2). Choose whatever suits you, but I will be showing off a fair bit of Apecs and I will be starting the project with SDL2, so you'll have to research how to start your game off independently. I will also be using [SDL-ttf](https://hackage.haskell.org/package/SDL-ttf) and [SDL-image](https://hackage.haskell.org/package/SDL-image), remember, if you are also using packages that have bindings to C you will also need to install them onto your system, not just the Haskell bindings. Now, let's show some code.\n\n> Note that I am importing SDL with `qualified`, so that every SDL function has SDL before it. I mainly do this in the main file as there's a lot going on. Do as you wish. Also, this won't compile yet due to us not having the `initialise` function implemented.\n\n```hs\nimport Apecs\nimport qualified SDL\nimport qualified SDL.Image(quit)\nimport qualified SDL.Font\n\n-- Uses templateHaskell to create the data 'World'\n-- also creates initWorld\nmakeWorld \"World\" []\n\nmain :: IO ()\nmain = do\n -- Initialise Apecs world\n world <- initWorld\n\n -- Initialise SDL\n SDL.initialize [SDL.InitVideo]\n SDL.Font.initialize\n\n -- Create a window and renderer\n window <- SDL.createWindow \"App\" SDL.defaultWindow\n renderer <-\n SDL.createRenderer window (-1)\n SDL.RendererConfig\n { SDL.rendererType = SDL.AcceleratedRenderer\n , SDL.rendererTargetTexture = False\n }\n\n -- Do any initialisation here!\n runSystem initialise world\n\n -- Display the game\n SDL.showWindow window\n\n -- Insert loop code here!\n\n -- Delay shutdown if you like?\n SDL.delay 1000\n\n SDL.destroyRenderer renderer\n SDL.destroyWindow window\n SDL.Image.quit\n SDL.Font.quit\n SDL.quit\n putStrLn \"Goodbye!\"\n exitSuccess\n```\n\nOkay, so here we have a basic main function that creates a world and then closes it. Nothing special. I even threw in [SDL.Delay](https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Time.html#v:delay) so you can see the window before it closes. Note that `SDL.Image` is initialised when used unlike the core and font variations, which is why only quit is imported here. This code isn't anything special so I should probably stop typing and move on to describing a simple game loop. But first, let's look at [Apecs' `makeWorld` function](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:makeWorld).\n\nIf you actually clicked the link above you would have noticed that it says \"turns into\" at some point. This function uses Template Haskell, and simply writes a lot of things for you. The reason that you will never find the `World` type is that it is actually created in the `makeWorld` function described, and so the function `initWorld` is specialised to the type created in `makeWorld`. The function `makeWorld` accepts a string which will become the type (in our case, \"World\" becomes `World`) along with a list of components we are yet to make. To sum it up, `makeWorld` is simply a template that creates the world type and a bunch of functions for said world for you which your entire game will revolve around.\n\n### Loop function\nNow for the loop function:\n\n```hs\nlet loop prevTicks secondTick fpsAcc prevFps = do\n ticks <- SDL.ticks\n payload <- map SDL.eventPayload <$> SDL.pollEvents\n let quit = SDL.QuitEvent `elem` payload\n dt = ticks - prevTicks\n calcFps = secondTick + dt > 1000\n newFps = if calcFps then fpsAcc + 1 else prevFps\n newFpsAcc = if calcFps then 1 else fpsAcc + 1\n newSecondTick = if calcFps then mod (secondTick + dt) 1000 else secondTick + dt\n\n -- React to input\n runSystem (handlePayload payload) world\n\n -- Update the world\n runSystem (step $ fromIntegral dt) world\n\n -- Set the background colour and clear the screen\n SDL.rendererDrawColor renderer $= V4 0 0 0 0\n SDL.clear renderer\n\n -- Render the world\n join $ runSystem (draw renderer newFps) world\n\n SDL.present renderer\n unless quit $ loop ticks newSecondTick newFpsAcc newFps\n\n-- Begin looping\nloop 0 0 0 0\n```\n\nYou can either put this in a let block inside the `main` function, or you can make it it's own thing. Up to you. What matters is that you understand that we are recursively looping almost indefinitely until the user closes the window (ie, giving SDL the `QuitEvent`). Don't worry if there's a lot of stuff you don't understand, take a moment and research the functions presented to you.\n\nI could probably have named the variables better, but I've essentially made a simple FPS counter for this tutorial. Yes, it could probably be better and yes, there's probably [something like this](https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Framerate.html) that does it for you. I just wanted to illustrate how ticks and time work here.\n\n### Ticks\nThere are 1000 ticks in a second (1 tick is 1 millisecond), and the `ticks` function allows us to see how many ticks have passed since SDL was initialised. We can use this to work out the time since the previous frame (`dt` or [*delta time*](https://en.wikipedia.org/wiki/Delta_timing)). Here, I am using `secondTick` to time seconds, and so `calcFPS` is `True` when a second has passed. The `newFPS` value will either display the fps for the previous second (`prevFps`), or it will display the current running total + 1 stored in `fpsAcc`. Finally, the timer tracking seconds is reset. It's a bit ugly, but this a very easy and primitive way of tracking FPS in the early days, not that we are rendering any text yet. Let's start getting into the basics of Apecs.\n\n## Apecs Components\n\n### Remembering Types\nOkay, so there are a couple of lines that won't compile as we haven't implemented them yet. Let me take the time to explain the role of ['runSystem'](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:runSystem). In Apecs, `System` is a monad that most of your code will produce at some point. I'm not going to talk about what a monad really is as that's a hot topic, but I can show what they can do. To put it simply, `runSystem` ***does*** something. It can or *will* execute side effects and can produce multiple side effects at once. The `System` monad is how you will manipulate your game.\n\nHere's a refresher on [creating types in Haskell](https://wiki.haskell.org/Constructor). We will need all of these if we're going to get anywhere with Haskell.\n\n* **`type`:** A *type synonym*. You can replace the occurence of your type with what it represents, it does nothing else. Functions can accept types in addition to what the type represents, it's just an alias. Example:\n```hs\ntype String = [Char]\ntype LongThing = (Int, Int, Int, Int, Int)\n```\n* **`data`:** A *type constructor*. You can craft your own types out of other types (think classes or structs in other languages). Functions that take or return your type will not accept anything but your type, and you will have to deconstruct it to access the contents. Example:\n```hs\ndata Bool = True | False\ndata Maybe a = Just a | Nothing\ndata Action = MoveTo (V2 Int) | Attack Entity | Cast Spell | Wait Int\n```\n* **`newtype`:** A *type constructor* that acts as a wrapper for a single type. Your type will act just like it would if you used `data`, but is more efficient. If you are simply wrapping your type around something, use this. Example:\n```hs\nnewtype PositionComponent = PositionComponent (V2 Double)\n```\n\n### Creating Components\nNow, let's create some simple components to manipulate. Examine the code below in addition to modifying our `makeWorld` call. Note that `V2` is contained within `SDL.Vect`, which re-exports the package [`Linear`](https://hackage.haskell.org/package/linear) (ie, if you are using SDL, you do not need to install `Linear` as it comes with it. `Linear` comes with lots of nice types like `V2`, `V3` and `V4`, go take a look.)\n\n```hs\n-- Global component, exists outside of entities\n-- Used for managing the passage of time\nnewtype Time = Time Double deriving Show\ninstance Semigroup Time where (<>) = mappend\ninstance Monoid Time where mempty = Time 0\ninstance Component Time where type Storage Time = Global Time\n\n-- Unique component, either one or none exists\ndata Player = Player deriving Show\ninstance Component Player where type Storage Player = Unique Player\n\n-- Position of game entities\nnewtype Position = Position (V2 Double) deriving Show\ninstance Component Position where type Storage Position = Map Position\n\n-- Name of game entities\nnewtype Name = Name String deriving Show\ninstance Component Name where type Storage Name = Map Name\n\n-- Uses template Haskell to create the data 'World'\n-- also creates initWorld\nmakeWorld \"World\" [''Time, ''Player, ''Position, ''Name]\n```\n\nSo here we have three components. The first, `Time`, is a `Global` component. This means that there's ***only one of it at any one time, and it belongs to no entity***. This is appropriate as time is, well, global. Although, it does actually belong to an entity secretly - an entity in Apecs (and many other implementations) is just an integer to reference components together. Global components are stored on entity *-2*, which will never be interfered with with normal usage of apecs.\n\nTime is a newtype - we would have liked to use just a `Double`, but because we need to provide our own instances of typeclasses, we need to `newtype` it as type synonyms don't have their own implementations. We implement the `Component` typeclass so that apecs knows what kind of component it is. You can see the different kinds of entities [here](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Stores.html). It also needs to implement instances of `Semigroup` (usually you can just specify `mappend`, it's worked for me this far!), and `Monoid` (specify what an 'empty' component looks like, as this is the initial state of the component as it exists from the beginning of the game).\n\nSecond, we have the `Player` component. This type has only one data constructor, `Player`. The purpose of this component is to simply mark which entity is the player - ***there can only be unique entity at once, giving it to a new entity removes it from the previous***. Nothing much else to say about this for now, but it will come into play later.\n\nFinally, we have `Position`. Again, this is a newtype so that we can create instances of `Component` - *every component in Apecs needs this instance, so try to provide these to prevent [Orphan Instances](https://wiki.haskell.org/Orphan_instance).* Even though that the implementation of `V2` is the following..\n```hs\ndata V2 a = V2 a a\n```\n.. It is still a single piece of data in the same way that `(a,b)` is also a single piece of data (a tuple containing two fields of possibly different types).\n\nAs a final note, notice how `makeWorld` now contains components. This piece of template Haskell is going to take what we've done and allow our component types to be used within the Apecs `World`. This means that everything found in [Apecs.System](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-System.html) will now be compatible with your types.\n\nOkay, so maybe that was a tough section, maybe it wasn't. Maybe you're learning something or maybe you're upset that I've done something in a beginnerish way. Either way, this code should be close to compilation and should be enough to demonstrate some basics of Apecs.\n\n## Systems\n\n### Side Effects in Monads\nIn an [Entity Component System](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system) such as Apecs, *systems* are what make the world go round. Normally in C++ or C#, I'd make my ECS seperate from a few things baked into the engine, but with Apecs I have to imagine a lot of things as a global component instead. The game's map, texture caches and other assets will most likely manifest as a global component here, if you wouldn't already have implemented things in this way.\n\nUp to this point in the tutorial, I've given code examples that haven't given much room for flexibility and I assume that you've been following along with me. For this area though, I'm going derail a little bit and just try to show off what apecs can do. I'll provide usable, relevant code, but obviously what you choose to do depends on your game. This section is going to be fairly lengthy and have a lot of code, but if you follow along and understand the methodology I'm sure that you can apply what I give to your own code.\n\nFirstly, some usage. Apecs has a function that I've touched on already called ['runSystem'](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:runSystem). This function will execute side effects contained within the monad and therefore strip away the `System` part. Here's an example of how this may look with the IO monad:\n```hs\nmain :: IO ()\nmain = do\n -- The following will be executed just like how\n -- runSystem would execute one of your systems\n putStrLn \"Here's a basic print function!\"\n\n -- The following will NOT be run..\n let funcThatProducesIOIO = pure $ putStrLn \"Here's an IO(IO())!\"\n foo <- funcThatProducesIOIO\n\n -- ..until it is called like so\n foo\n\n -- That was because 'foo' has type IO (), but this\n -- is simply the storage of the monad, not execution\n\n -- pure wraps the argument inside the monad, leading to\n -- IO (IO ()), which when bound to foo, creates type IO ()\n -- This means that one layer of IO has been executed but\n -- not the second.\n\n -- This pattern is dumb, binding something just to call it.\n -- This will work instead:\n\n join funcThatProducesIOIO\n\n```\n\nHopefully that code above makes some sense. Because the main thread will execute IO in order to actually make something happen with the program, anything that has type `IO ()` will be executed automatically. The final example was something I wanted to mention because of some confusion with monads that a few people have asked me. When we bind something using `<-`, the monad on the right is executed to produce the thing inside it. `IO (String)` would produce a `String`, for instance (this could be reading in from the keyboard?). This means that if the thing produced is yet another monad, like IO (), the thing on the left is not executed, and `join` is a nice shortcut to save you binding and executing as demonstrated above.\n\nWhy am I telling you this? Because no matter whether you use SDL or not, you will want to perform IO to make things appear on screen. If you have a system which produces IO, like a render system, then you will need to use `join` in order to execute the side effects contained within the monad you retrieved.\n\n### Easy System Type Synonym\nNext up, a simple type synonym. The following will make using Apecs a lot easier:\n```hs\n-- Easy type synonym for systems\ntype System' a = System World a\n```\nRemember, this is a type synonym, it doesn't actually affect your code in any way. It simply saves you from typing and keeps reading type signatures easier. All `System World a` means is that, assuming your world from your `makeWorld` function was named ``\"World\"``, that this system operates within your world and can make a change in some way.\n\n### Writing the Initialisation System\nIf we scroll up to our initialisation code, you will see we do:\n```hs\n-- Do any initialisation here!\nrunSystem initialise world\n```\nIt is now time to write our `initialise` system. This system is simply going to act as our kickstart to the game, add our player, do things. I'm sure you can guess what your game will need to do to set things up. One final thing I need to mention is that [a System has the following type](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Core.html#t:SystemT): `newtype SystemT w m a `. This may not mean anything at first, but the documentation clearly states that the monad `m` used in a system is in fact compatible with IO. Anything to do with IO can be performed as a part of a system, which may help with debugging.\n\nLets go! Here's a sample initialisation system:\n```hs\n-- The type of this function is System' (), so when we open up\n-- a 'do' block, we are allowing us to bind the contents of System' monads\n-- as well as executing side effects of any other System' () easily.\ninitialise :: System' ()\ninitialise = do\n\n -- Make sure you use liftIO to get the following to compile,\n -- we are returning System' (), not IO (), hence the lift.\n -- Lift is used to lift a function producing a\n -- monad of one type (IO) into another (System'()).\n liftIO $ putStrLn \"Let's do some IO just to prove we can!\"\n\n -- Let's initialise the time monad, even though we don't\n -- really have to as Apecs handles that for us.\n\n -- 'set' produces a System' (), which means this line\n -- will be executed as part of this system.\n set global $ Time 0\n\n -- Another two System' ()s, this time we're creating entities\n newEntity (Player, Name \"Lola\", Position $ V2 0 0)\n newEntity (Name \"Harold\", Position $ V2 0 0)\n```\n\nRemember, we're looking at the functions [on the Apecs Hackage docs](https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-System.html) for all of our inspiration on what functions to use. It is pretty self explanatory when you get the hang of it I promise. Make sure you're looking at the most up to date version of all your documentation.\n\nHonestly, if you understand how these all work, how we compose monads to execute side effects and how Apecs allows us to run these System's from the main thread to play our game, things will get much easier. If not, fear not, you'll get there. Hopefully some more examples will help.\n\n### Writing the Step System\nRecall that we call the following during our main game loop:\n```hs\n-- Update the world\nrunSystem (step $ fromIntegral dt) world\n```\n\nThis is our second system. This will be more important than the previous, with this being a collection of every system you require execution of each frame. Notice how we are calling this `runSystem` - the system we pass to it has some extra parameters inside. When that parameter is evaluated, `step` will accept `dt` and evaluate into a `System' ()` as you'd expect of any programming language in the same way that passing `(1 + 1)` would be equivalent to an `Int`, as the function:\n```hs\n(+) :: Num a => a -> a -> a\n```\nhas been fully evaluated.\n\nThis means that our new system looks similar to the following:\n\n```hs\n-- Okay, so we have access to delta time now.\n-- This allows us to animate or simulate stuff.\n-- Notice how we can execute other systems inside\n-- this system with no problems.\nstep :: Double -> System' ()\nstep dT = do\n moveCharacters dT\n rootPlayer\n\n-- The function cmap below finds every entity with a Position\n-- and rewrites it with new values - adding dT to the x and y values.\n-- 'cmap' is another function producing System' ()\nmoveCharacters :: Double -> System' ()\nmoveCharacters dT =\n cmap (\\(Position (V2 x y)) -> Position $ V2 (x + dT) (y + dT))\n\n-- Apecs has a lot of magic involved, look at this:\nrootPlayer :: Double -> System' ()\n cmap (\\(Player, Position _) -> Position $ V2 0 0)\n\n-- This iterates on all entities with both a Player component and\n-- Position component, however, Player is unique, so this is only\n-- applied to the player.\n\n-- This is actually a bit dumb, as we're operating on the player twice,\n-- so let's rewrite that first call:\n\n-- Not is an Apecs Data Constructor used for the exclusion of a component.\n-- We have to specify the type of Not as GHC cannot infer this on its own.\n-- This will operate on entities without a Player component.\nmoveNonPlayerCharacters :: Double -> System' ()\nmoveNonPlayerCharacters dT = do\n cmap (\\(Position (V2 x y), Not :: Not Player) -> Position $ V2 (x + dT) (y + dT))\n```\n\n### Apecs Magic with Systems\nIn the above examples, the function `cmap` allowed us to read components and overwrite them. There's a lot more to it, and once you get used to the different approaches you'll have to commend Apecs for the amount of work put into it.\n\nAny of the functions in the Apecs documentation that take or write `Components` (or `c`, as the documentation uses types and magic to make things polymorphic) can take a variety of different forms. As you saw above, you can read multiple components as we did with `(Player, Position _)` (note that in that case we used `_` to ignore the parameter, as we were overwriting the position). You can actually write to multiple components too! As long as the components are produced as a tuple, just like the example just given, then you can return multiple components too. Not that ignoring any input components will leave them alone - we didn't need to write `Player` again to preserve it on the entity.\n\nI'm going to just throw some examples that I can think of at you now. I'll talk about what they do after each segment. I'm going to be calling functions and using Components that we haven't defined, the idea being that these are just to demonstrate different methods of using Apecs.\n\n```hs\neveryoneChasePlayer :: System' ()\neveryoneChasePlayer = do\n [(Player, Position p)] <- getAll\n cmap (\\(Position p', Not :: Not Player) ->\n Position $ moveTowards p' p)\n```\n\nHere, using `do` syntax, we can get components attached to the `player` very easily. When there's only one element in the list we can pattern match on it just like a tuple, but this may crash your program if the `Player` does not exist or if you don't grab a unique component and therefore have more than one entity. By grabbing the player's position, we can pass that to a function called `moveTowards` which is in charge of manipulating the first argument so that it gets closer to the second. This function is pure, as `cmap` is the function producing the `System' ()` monad, so you can forget about Apecs and focus on your logic when writing it.\n\n```hs\ndebugCharacters :: System' ()\ndebugCharacters = cmapM_ (\\(Name n, Entity e) ->\n liftIO $ putStrLn (\"Entity \" ++ show e ++ \" is named: \" ++ n))\n```\n\nHere's a simple template you can use for debugging. As previously mentioned, `System' ()` supports `MonadIO`, allowing you to perform `IO` inside it. `cmapM` allows us to read components and iterate over them monadically (basically we can treat each iteration as another `System' ()`), which allows us to perform side effects instead of being locked into a pure environment like with the previous example. If we used `do` here, we could even call another system too!\n\nAlso, notice how we found the `Entity` here - whenever we use `getAll` or `cmap` or anything that gets components (other than `get`), we can allocate bindings for the `Entity` these components belong to. `Entity` is just a newtype for `Int`, so `e :: Int` in this case, hence why we `show` it. The `n` is simply a string which doesn't require the use of `show`. If we want to actually use the `Entity`, be sure to wrap the `Int` back in an `Entity` or simply grab the entity as `e :: Entity` rather than pattern matching as we did here.\n\nFinally, the `cmapM_` function (notice the `_`) that we used is the same as `cmapM`, but it doesn't write anything. It's job is to read and provide the a way of monadically iterating. If we wanted to change the name of the entity, using `cmapM` instead would allow us to return something out of the monadic iteration to write the entity with. Here's an example of writing components with `cmapM`:\n\n```hs\napplyGravity :: Double -> System' ()]\napplyGravity dT = cmapM (\\(Position (V2 x y), e :: Entity) -> do\n let gY = y + (dT * 0.5)\n y' = max gY 0\n liftIO $ putStrLn (\"Entity \" ++ show e ++ \" moved from \" ++ show y ++ \" to \" ++ show y')\n pure $ Position (V2 x y'))\n```\n\nSo here we have an example of using `let` to make calculations easier, along with some `IO`, getting the `Entity` and finally overwriting `Position` components to apply gravity (in SDL and many other frameworks, the top left is `(0,0)`, so positive `y` moves things down).\n\n```hs\nfireWeapon :: V2 Double -> Double -> System' ()\nfireWeapon (V2 i j) -> speed = do\n [(Player, p :: Position, Weapon ammo, e :: Entity)] <- getAll\n when (ammo > 0) $ void $ do\n let ammoLeft = max 0 $ ammo - 1\n set e (Weapon ammoLeft)\n newEntity (Velocity (i * speed) (j * speed), p)\n```\n\nHere's an example of making a new entity while producing `System' ()`. When the side effects of this system are performed, we begin by grabbing the `Entity` with the `Player` component along with some other components. Remember, we need to make sure beforehand the player has these components otherwise the pattern matching will fail, and we can only pattern match here because we know we are only going to have one element in this list.\n\nWe then set the `Weapon` component on the player to a new value. The function `set` can be used regardless of if it already exists on the entity or not, and so can be a better option than `cmap`. Additionally, `set` requires you to provide the entity you're modifying, meaning that if we weren't operating on a unique entity then `cmap` wouldn't be as good - `cmap` iterates over ***every*** entity with the matching components. You have more control with `set`, just make sure that you're not wasting your time when you could use `cmap` or any other Apecs function.\n\nLastly, notice our use of `when` and `void`. The function `when` is exported by `Control.Monad`, and is pretty much equivalent to the following:\n```hs\nwhen' :: Bool -> m () -> m ()\nwhen bool func =\n if bool\n then func\n else pure ()\n```\nBasically, `when` will do ***nothing*** when it's logic is false. There's the reverse of when too, called `unless`. The other function, `void` will execute execute the side effects of the monad passed to it, but discard the value returned. When we use `newEntity` to create a new Entity, the Entity created is returned as `System' (Entity)`. Since we want this function to return a blank `System' ()`, we need to just ignore what is returned (don't worry, the entity is not deleted) so that the whole thing type checks.\n\n### Writing the Event Handler System\nOkay, this section is going to start combining SDL code with Apecs. There are plenty of guides on how to use SDL, so I'm going to show the code first and mention anything important after. Remember that SDL gives you a list of all the events that have occurred since the last poll and you need to handle them all individually. I have not yet implemented any code to check for modifier keys like `shift` or `ctrl`. This will use many of the techniques shown in the previous section so hopefully you can follow along easily.\n\n```hs\n-- Global component used for changing gamestates\ndata GameMode = Standard | Look deriving (Show, Eq)\ndata GameState = Game GameMode | Interface deriving (Show, Eq)\ninstance Semigroup GameState where (<>) = mappend\ninstance Monoid GameState where mempty = Game Standard\ninstance Component GameState where type Storage GameState = Global GameState\n\n-- Handle the entire event payload\nhandlePayload :: [EventPayload] -> System' ()\nhandlePayload = mapM_ handleEvent\n\n-- The main event handler function for dealing with keypresses\nhandleEvent :: EventPayload -> System' ()\nhandleEvent (KeyboardEvent ev) = handleKeyEvent ev\nhandleEvent _ = pure ()\n\n-- For the handling keyboard events only\nhandleKeyEvent :: KeyboardEventData -> System' ()\nhandleKeyEvent ev = do\n (state :: GameState) <- get global\n let code = keysymKeycode $ keyboardEventKeysym ev\n case keyboardEventKeyMotion ev of\n Pressed ->\n case state of\n Game mode -> gameAction mode code\n Interface -> postMessage \"Interface state not implemented yet\"\n Released -> pure ()\n\n-- For keyboard events that take place in the game\ngameAction :: GameMode -> Keycode -> System' ()\ngameAction mode k =\n let intents = lookup k defaultGameIntents in\n case mode of\n Standard ->\n case intents of\n Just (Navigate dir) -> navigate dir\n Just ToggleLook -> toggleLook mode\n Just Wait -> do\n postMessage \"You wait..\"\n playerActionStep 100\n _ -> pure ()\n Look ->\n case intents of\n Just (Navigate dir) -> moveReticule dir\n Just ToggleLook -> toggleLook mode\n _ -> pure ()\n\n-- Initial bindings for intents\ndefaultGameIntents :: [(Keycode, GameIntent)]\ndefaultGameIntents =\n [ (KeycodeUp , Navigate C.Up)\n , (KeycodeLeft , Navigate C.Left)\n , (KeycodeDown , Navigate C.Down)\n , (KeycodeRight , Navigate C.Right)\n , (KeycodeSemicolon, ToggleLook)\n , (KeycodeW, Wait)\n ]\n```\n\nI first have created a component called `GameState`, maybe that's not the best name. This `Global` component is basically going to help us work out the context of what's on screen. For instance, our inputs on the arrow keys may move the player in game, but on a menu it will do something else. I haven't done any of the interface stuff yet, but I have two different modes for the actual game. I'm making an Roguelike RPG, and one requirement is that the player can look at things without moving and interacting with anything. This component allows me to firstly see whether we're in game or not and secondly, if we are in game, what we are doing. These things are very likely to change to suit whatever game you're making, but I'm hoping for the purposes of this tutorial you can see what I'm getting at.\n\nThe `handlePayload` function itself starts by taking the entire payload and performing `mapM_` on it - `mapM_` is not an Apecs function but rather one that is found in `Control.Monad`. If you were following what the `cmapM_` function did earlier, this might already be clear. This function is very similar except that instead of iterating over Apecs components, it iterates over whatever `Traversable` class you pass it, in this case, a list. We are using the `mapM_` version of map because a normal `map` function doesn't give us the monadic context we need to do this cleanly, whereas `mapM_` allows us to produce a `System' ()` for each element of the list, and the `_` simply discards any data that isn't a side effect, as we aren't using anything. This takes us into the `handleEvent` function, which now only has to worry about a single `SDL.Event`.\n\nThe `handleEvent` system I've written does simple pattern matching on the type of event it is given. If the event is a `KeyboardEvent`, it is opened up to expose the event itself and is then passed on to `handleKeyEvent`. I haven't thought about other `SDL.Event`s yet, as our main loop already handles checking for the `QuitEvent`, which means everything I deem important has been handled. Maybe you want something to happen when the screen is resized or if the mouse is clicked, you should go and check out [the docs](https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Event.html#t:EventPayload) to find what kind of events you might need, and what data those events contain.\n\nOur `handleKeyEvent`'s job is to direct the flow of the program to where it needs to go next. This is now getting to the point where different games will do different things. My game isn't interested in any key releases, so if the type of `keyboardEventKeyMotion ev` matches `Released` I don't do anything. Otherwise, I call my own function, `gameAction` along with the current mode and the keycode. Remember that anywhere inside any of these functions you can call as many `System' ()` functions as you like to compose the monad. Apecs has allowed us to keep our code clean and healthy while also giving us room to do whatever we like as long as we construct `System' ()` as the output, which as we know, is really easy when you know how.\n\n### Writing the Draw System\nRecall that the draw system interacts with the `IO` monad. I've shown already how you can use `liftIO` to execute `IO` from within a `System' ()`, but I've also shown how returning `System (IO ())` can also be used to draw when the `join` function (found in `Control.Monad`) is used. You should have enough information to get a basic drawing system going.\n\nOne of the hardest challenges you'll face early on is managing your textures, fonts and other assets. It's easy to create a `Texture` component and give each `Entity` the texture it's going to render with, however, this means that having five entities that show the same thing will have the same texture loaded five times over.\n\nI've created `Global` components for `Textures` and `Fonts` which implement `HashMap`s (found in `Data.HashMap`). A `HashMap` is like a normal map but it runs a lot faster as it isn't ordered. My `draw` system then passes the assets found inside these components to whatever functions need them. You can of course, just use `IO` in the main loop and pass everything to the `draw` system to avoid loading things multiple times, but this would mean having all of your assets loaded at once. Eventually, I plan on scanning all of my `Sprite` components and loading / unloading assets inside the hashmap depending on what textures are required. Here's the current code:\n\n```hs\n-- Turns a list of key value pairs into a hashmap for a resource component\ncreateResourceMap :: [(String, a)] -> HM.Map String a\ncreateResourceMap = foldl (\\m (k, v) -> insert k v m) empty\n\n-- Types for creating textures\ntype TexResource = (String, Texture)\ntype TextureMap = HM.Map String Texture\n\n-- Create a TextureMap with initial filepaths\nloadTextures :: Renderer -> [FilePath] -> IO [TexResource]\nloadTextures r = traverse getTex\n where getTex p = do\n tex <- loadTexture r p\n pure (p, tex)\n\n-- Types for creating fonts\ntype FontResource = (String, Font)\ntype FontMap = HM.Map String Font\n\n-- Create a FontMap using initial filepaths\nloadFonts :: [(FilePath, PointSize)] -> IO [FontResource]\nloadFonts = traverse getFont\n where getFont (p, s) = do\n font <- load p s\n pure (p, font)\n\n-- Global store of all textures\nnewtype Textures = Textures TextureMap\ninstance Component Textures where type Storage Textures = Global Textures\ninstance Semigroup Textures where (<>) = mappend\ninstance Monoid Textures where mempty = Textures HM.empty\n\n-- Global store of all fonts\nnewtype Fonts = Fonts FontMap\ninstance Component Fonts where type Storage Fonts = Global Fonts\ninstance Semigroup Fonts where (<>) = mappend\ninstance Monoid Fonts where mempty = Fonts HM.empty\n\n-- Create System' (IO ()) for everything depending on item drawn\ndraw :: SDL.Renderer -> Int -> System' (IO ())\ndraw renderer fps = do\n Textures texs <- get global\n Fonts fonts <- get global\n let uiFont = HM.lookup \"Assets/Roboto-Regular.ttf\" fonts\n sequence_ <$> sequence\n [ drawComponents $ renderSprite renderer texs\n , drawComponents $ renderReticule renderer\n , displayFps renderer fps uiFont\n ]\n\n-- Produce a system used for drawing\ndrawComponents :: Get World c => (c -> Position -> IO ()) -> System' (IO ())\ndrawComponents f = cfold (\\img (p, comp) -> img <> f comp p) mempty\n\n-- Render textures\nrenderSprite :: SDL.Renderer -> TextureMap -> Sprite -> Position -> IO ()\nrenderSprite r ts (Sprite fp rect) (Position p) =\n case HM.lookup fp ts of\n Just tex -> SDL.copyEx r tex (Just $ toCIntRect rect) (Just (SDL.Rectangle (P $ toCIntV2 p) tileSize')) 0 Nothing (V2 False False)\n _ -> pure ()\n\n-- Render the target reticule\nrenderReticule :: SDL.Renderer -> Reticule -> Position -> IO ()\nrenderReticule r (Reticule on) (Position p)\n | not on = pure ()\n | on = do\n rendererDrawColor r $= V4 255 255 255 20\n fillRect r $ Just $ Rectangle (P $ toCIntV2 p) tileSize'\n\n-- Display FPS\ndisplayFps :: SDL.Renderer -> Int -> Maybe SDL.Font.Font -> System' (IO ())\ndisplayFps r fps Nothing = pure $ pure ()\ndisplayFps r fps (Just f) =\n pure $ renderSolidText r f (V4 255 255 255 255) (\"FPS: \" ++ show fps) (V2 0 0) False\n\n-- Render solid text\nrenderSolidText :: SDL.Renderer -> SDL.Font.Font -> SDL.Font.Color -> String -> V2 Double -> Bool -> IO ()\nrenderSolidText r fo c s p = renderText r fo (SDL.Font.solid fo) c s (toCIntV2 p)\n\n-- Render text to the screen easily\n-- renderSolidText calls this\nrenderText :: SDL.Renderer -> SDL.Font.Font -> (SDL.Font.Color -> Data.Text.Text -> IO SDL.Surface) ->\n SDL.Font.Color -> String -> V2 CInt -> Bool -> IO ()\nrenderText r fo fu c t (V2 x y) center = do\n let text = Data.Text.pack t\n surface <- fu c text\n texture <- SDL.createTextureFromSurface r surface\n SDL.freeSurface surface\n fontSize <- SDL.Font.size fo text\n let (w, h) = (fromIntegral *** fromIntegral) fontSize\n unless center $\n SDL.copy r texture Nothing (Just (Rectangle (P $ V2 x y) (V2 w h)))\n when center $ do\n let x' = x - fromIntegral (fst fontSize `div` 2)\n SDL.copy r texture Nothing (Just (Rectangle (P $ V2 x' y) (V2 w h)))\n SDL.destroyTexture texture\n```\n\n> This code is just a rough draft just so that I can see things on screen. While I recommend beginners using this so that they can start having fun with Haskell, I ***deeply encourage*** you to make optimisations wherever you can and tailor everything to your game. The `renderText` function is severely inefficient and so I'm going to be trying to batch all of the text onto one surface before creating a texture out of it. This code is ***not good***.\n\nOh my gosh, what a lot of code. I'm sorry for just dumping so much, but at the same time there's no better way to illustrate how I try to do things. This might be pretty complex and hard to read for the beginners reading this, but all I can say is that you should begin by looking at the function types for each block of code and understanding how the functions use each other. Most importantly, see how we go from producing `IO ()` in `renderText` and `renderSolidText` to producing `System' (IO ())` when bundled with `displayFPS` or `drawComponents`. The `drawComponents` function simply uses `cfold` to combine all of the `IO ()` monads into one, before wrapping `System' ()` around it like all the other Apecs functions do.\n\n## Conclusion\n\nI'm sorry for the huge amount of code pastes, but hopefully there's at least something written in this blog post that will teach someone something. My real intent is to encourage the usage of Haskell for the creation of small games where we no longer need performance as much as we used to. Hopefully this inspires of more programmers and more frameworks to use Haskell so that writing in a functional language becomes less of an alien idea. I want to see indie developers start embracing the power of high-level languages to make development easier on their already-difficult lives. If people can make [cool games in JavaScript](https://store.steampowered.com/app/497800/Golden_Krone_Hotel/), then why not Haskell?",
"json_metadata": "{\"tags\":[\"blog\",\"programming\",\"haskell\",\"guide\",\"games\"],\"links\":[\"https://blog.aas.sh/posts/2018-09-10-Making-A-Game-With-Haskell-And-Apecs/\",\"https://blog.aas.sh/posts/2018-06-09-Of-Boxes-And-Threads/\",\"http://haskellbook.com/\",\"https://docs.haskellstack.org/en/stable/README/\",\"https://www.stackage.org/\",\"https://github.com/ghcjs/ghcjs\",\"https://hackage.haskell.org/package/apecs\",\"https://hackage.haskell.org/package/sdl2\",\"https://hackage.haskell.org/package/SDL-ttf\",\"https://hackage.haskell.org/package/SDL-image\",\"https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Time.html#v:delay\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:makeWorld\",\"https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Framerate.html\",\"https://en.wikipedia.org/wiki/Delta_timing\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs.html#v:runSystem\",\"https://wiki.haskell.org/Constructor\",\"https://hackage.haskell.org/package/linear\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Stores.html\",\"https://wiki.haskell.org/Orphan_instance\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-System.html\",\"https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system\",\"https://hackage.haskell.org/package/apecs-0.5.0.0/docs/Apecs-Core.html#t:SystemT\",\"https://hackage.haskell.org/package/sdl2-2.4.1.0/docs/SDL-Event.html#t:EventPayload\",\"https://store.steampowered.com/app/497800/Golden_Krone_Hotel/\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}2018/08/29 00:59:03
2018/08/29 00:59:03
| parent author | aas-sh |
| parent permlink | haskell-for-beginners |
| author | steemitboard |
| permlink | steemitboard-notify-aas-sh-20180829t005902000z |
| title | |
| body | @aas-sh, thank you for supporting @steemitboard as a witness. [](http://steemitboard.com/@aas-sh) Here is a small present to show our gratitude <sub>_Click on the badge to view your Board of Honor._</sub> Once again, thanks for your support! |
| json metadata | {"image":["https://steemitboard.com/img/notify.png"]} |
| Transaction Info | Block #25478326/Trx dafc62e49ca1165a06f12515b15b48d4afdeb8dc |
View Raw JSON Data
{
"trx_id": "dafc62e49ca1165a06f12515b15b48d4afdeb8dc",
"block": 25478326,
"trx_in_block": 0,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-29T00:59:03",
"op": [
"comment",
{
"parent_author": "aas-sh",
"parent_permlink": "haskell-for-beginners",
"author": "steemitboard",
"permlink": "steemitboard-notify-aas-sh-20180829t005902000z",
"title": "",
"body": "@aas-sh, thank you for supporting @steemitboard as a witness.\n\n[](http://steemitboard.com/@aas-sh) Here is a small present to show our gratitude\n<sub>_Click on the badge to view your Board of Honor._</sub>\n\nOnce again, thanks for your support!",
"json_metadata": "{\"image\":[\"https://steemitboard.com/img/notify.png\"]}"
}
]
}aas-shvoted for witness @steemitboard2018/08/28 15:58:12
aas-shvoted for witness @steemitboard
2018/08/28 15:58:12
| account | aas-sh |
| witness | steemitboard |
| approve | true |
| Transaction Info | Block #25467512/Trx 8c3af099b6fa0ee6fcb03b54a675b0abcd14b35c |
View Raw JSON Data
{
"trx_id": "8c3af099b6fa0ee6fcb03b54a675b0abcd14b35c",
"block": 25467512,
"trx_in_block": 19,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-28T15:58:12",
"op": [
"account_witness_vote",
{
"account": "aas-sh",
"witness": "steemitboard",
"approve": true
}
]
}jbergenupvoted (100.00%) @aas-sh / get-started-with-programming2018/08/27 03:03:36
jbergenupvoted (100.00%) @aas-sh / get-started-with-programming
2018/08/27 03:03:36
| voter | jbergen |
| author | aas-sh |
| permlink | get-started-with-programming |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25423245/Trx 5ac38ad4b6dc4d0d2aa148bd692254abb1187d2f |
View Raw JSON Data
{
"trx_id": "5ac38ad4b6dc4d0d2aa148bd692254abb1187d2f",
"block": 25423245,
"trx_in_block": 22,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-27T03:03:36",
"op": [
"vote",
{
"voter": "jbergen",
"author": "aas-sh",
"permlink": "get-started-with-programming",
"weight": 10000
}
]
}2018/08/26 22:17:06
2018/08/26 22:17:06
| parent author | aas-sh |
| parent permlink | haskell-for-beginners |
| author | steemitboard |
| permlink | steemitboard-notify-aas-sh-20180826t221705000z |
| title | |
| body | Congratulations @aas-sh! You have completed the following achievement on Steemit and have been rewarded with new badge(s) : [](http://steemitboard.com/@aas-sh) Award for the number of upvotes <sub>_Click on the badge to view your Board of Honor._</sub> <sub>_If you no longer want to receive notifications, reply to this comment with the word_ `STOP`</sub> > Do you like [SteemitBoard's project](https://steemit.com/@steemitboard)? Then **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**! |
| json metadata | {"image":["https://steemitboard.com/img/notify.png"]} |
| Transaction Info | Block #25417516/Trx 6f91d74c1c4d118c221e7d994788da48d95ddb23 |
View Raw JSON Data
{
"trx_id": "6f91d74c1c4d118c221e7d994788da48d95ddb23",
"block": 25417516,
"trx_in_block": 1,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T22:17:06",
"op": [
"comment",
{
"parent_author": "aas-sh",
"parent_permlink": "haskell-for-beginners",
"author": "steemitboard",
"permlink": "steemitboard-notify-aas-sh-20180826t221705000z",
"title": "",
"body": "Congratulations @aas-sh! You have completed the following achievement on Steemit and have been rewarded with new badge(s) :\n\n[](http://steemitboard.com/@aas-sh) Award for the number of upvotes\n\n<sub>_Click on the badge to view your Board of Honor._</sub>\n<sub>_If you no longer want to receive notifications, reply to this comment with the word_ `STOP`</sub>\n\n\n\n> Do you like [SteemitBoard's project](https://steemit.com/@steemitboard)? Then **[Vote for its witness](https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1)** and **get one more award**!",
"json_metadata": "{\"image\":[\"https://steemitboard.com/img/notify.png\"]}"
}
]
}jacekw.devupvoted (100.00%) @aas-sh / get-started-with-programming2018/08/26 19:35:48
jacekw.devupvoted (100.00%) @aas-sh / get-started-with-programming
2018/08/26 19:35:48
| voter | jacekw.dev |
| author | aas-sh |
| permlink | get-started-with-programming |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25414290/Trx 036e41ad19001c98ee86073a81478b7948afa0df |
View Raw JSON Data
{
"trx_id": "036e41ad19001c98ee86073a81478b7948afa0df",
"block": 25414290,
"trx_in_block": 40,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T19:35:48",
"op": [
"vote",
{
"voter": "jacekw.dev",
"author": "aas-sh",
"permlink": "get-started-with-programming",
"weight": 10000
}
]
}jacekw.devupvoted (100.00%) @aas-sh / haskell-for-beginners2018/08/26 19:35:45
jacekw.devupvoted (100.00%) @aas-sh / haskell-for-beginners
2018/08/26 19:35:45
| voter | jacekw.dev |
| author | aas-sh |
| permlink | haskell-for-beginners |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25414289/Trx 5bfc86618851f7814e798ee4f150bb7b764d8f8f |
View Raw JSON Data
{
"trx_id": "5bfc86618851f7814e798ee4f150bb7b764d8f8f",
"block": 25414289,
"trx_in_block": 4,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T19:35:45",
"op": [
"vote",
{
"voter": "jacekw.dev",
"author": "aas-sh",
"permlink": "haskell-for-beginners",
"weight": 10000
}
]
}aas-shupvoted (100.00%) @aas-sh / haskell-for-beginners2018/08/26 19:27:39
aas-shupvoted (100.00%) @aas-sh / haskell-for-beginners
2018/08/26 19:27:39
| voter | aas-sh |
| author | aas-sh |
| permlink | haskell-for-beginners |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25414127/Trx 8e88ec3caaf2a32473898ccd2a85804a677ae725 |
View Raw JSON Data
{
"trx_id": "8e88ec3caaf2a32473898ccd2a85804a677ae725",
"block": 25414127,
"trx_in_block": 10,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T19:27:39",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "aas-sh",
"permlink": "haskell-for-beginners",
"weight": 10000
}
]
}aas-shupvoted (100.00%) @aas-sh / get-started-with-programming2018/08/26 19:27:24
aas-shupvoted (100.00%) @aas-sh / get-started-with-programming
2018/08/26 19:27:24
| voter | aas-sh |
| author | aas-sh |
| permlink | get-started-with-programming |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25414122/Trx bc20bf3b8a29d6720c442c0fcc3c71e25f9e5720 |
View Raw JSON Data
{
"trx_id": "bc20bf3b8a29d6720c442c0fcc3c71e25f9e5720",
"block": 25414122,
"trx_in_block": 24,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T19:27:24",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "aas-sh",
"permlink": "get-started-with-programming",
"weight": 10000
}
]
}sensationupvoted (100.00%) @aas-sh / get-started-with-programming2018/08/26 18:55:51
sensationupvoted (100.00%) @aas-sh / get-started-with-programming
2018/08/26 18:55:51
| voter | sensation |
| author | aas-sh |
| permlink | get-started-with-programming |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25413492/Trx a5deb4212637399409ed79d21e8c5fa04d12364e |
View Raw JSON Data
{
"trx_id": "a5deb4212637399409ed79d21e8c5fa04d12364e",
"block": 25413492,
"trx_in_block": 7,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T18:55:51",
"op": [
"vote",
{
"voter": "sensation",
"author": "aas-sh",
"permlink": "get-started-with-programming",
"weight": 10000
}
]
}sensationupvoted (100.00%) @aas-sh / haskell-for-beginners2018/08/26 18:55:33
sensationupvoted (100.00%) @aas-sh / haskell-for-beginners
2018/08/26 18:55:33
| voter | sensation |
| author | aas-sh |
| permlink | haskell-for-beginners |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25413486/Trx e8e29d427cd2dca846dc68686c47d553560abbda |
View Raw JSON Data
{
"trx_id": "e8e29d427cd2dca846dc68686c47d553560abbda",
"block": 25413486,
"trx_in_block": 8,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T18:55:33",
"op": [
"vote",
{
"voter": "sensation",
"author": "aas-sh",
"permlink": "haskell-for-beginners",
"weight": 10000
}
]
}zedpalupvoted (100.00%) @aas-sh / get-started-with-programming2018/08/26 18:09:27
zedpalupvoted (100.00%) @aas-sh / get-started-with-programming
2018/08/26 18:09:27
| voter | zedpal |
| author | aas-sh |
| permlink | get-started-with-programming |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25412564/Trx cd690a70ef07a71597a031759b51e796189e7452 |
View Raw JSON Data
{
"trx_id": "cd690a70ef07a71597a031759b51e796189e7452",
"block": 25412564,
"trx_in_block": 24,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T18:09:27",
"op": [
"vote",
{
"voter": "zedpal",
"author": "aas-sh",
"permlink": "get-started-with-programming",
"weight": 10000
}
]
}youngogmarqsupvoted (0.02%) @aas-sh / get-started-with-programming2018/08/26 17:52:48
youngogmarqsupvoted (0.02%) @aas-sh / get-started-with-programming
2018/08/26 17:52:48
| voter | youngogmarqs |
| author | aas-sh |
| permlink | get-started-with-programming |
| weight | 2 (0.02%) |
| Transaction Info | Block #25412231/Trx 58171c61e4b265718856c32dac19885f45a591b1 |
View Raw JSON Data
{
"trx_id": "58171c61e4b265718856c32dac19885f45a591b1",
"block": 25412231,
"trx_in_block": 17,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:52:48",
"op": [
"vote",
{
"voter": "youngogmarqs",
"author": "aas-sh",
"permlink": "get-started-with-programming",
"weight": 2
}
]
}aas-shpublished a new post: get-started-with-programming2018/08/26 17:47:39
aas-shpublished a new post: get-started-with-programming
2018/08/26 17:47:39
| parent author | |
| parent permlink | programming |
| author | aas-sh |
| permlink | get-started-with-programming |
| title | Get started with programming! |
| body | @@ -6023,16 +6023,35 @@ acrity%5D( +https://blog.aas.sh /content @@ -15868,16 +15868,35 @@ ntures%5D( +https://blog.aas.sh /content |
| json metadata | {"tags":["programming","beginners","guide","how","start"],"image":["https://blog.aas.sh/content/2017-02/alacrity.gif","https://blog.aas.sh/content/2017-04/vimadventures.gif"],"links":["https://blog.aas.sh/posts/2017-04-11-Start-Programming/","https://www.codecademy.com/","https://cs50.harvard.edu/","https://www.edx.org/course/introduction-computer-science-harvardx-cs50x","https://www.codeavengers.com/","http://github.com","https://gitter.im/","http://www.monogame.net/","https://www.ubuntu.com/","https://blog.aas.sh/Mistakes","http://GitHub.com","https://guides.github.com/activities/hello-world/","https://education.github.com/pack","https://vim-adventures.com/","https://github.com/Crysikrend/emacs","http://orgmode.org/","http://brackets.io/","https://atom.io/","https://www.sublimetext.com/","https://www.visualstudio.com/","https://www.jetbrains.com/rider/","https://www.unrealengine.com/","http://reddit.com","http://boards.4chan.org/g/","discordapp.com","https://discordapp.com/invite/gamedev","https://discordapp.com/invite/wdg","http://github.com/crysikrend/sprinty","https://www.libsdl.org/","http://BestInSlot.gg","http://twitter.com/crysikrend"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25412128/Trx d768283d942872a280addd984df8b03a2265de1a |
View Raw JSON Data
{
"trx_id": "d768283d942872a280addd984df8b03a2265de1a",
"block": 25412128,
"trx_in_block": 6,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:47:39",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "programming",
"author": "aas-sh",
"permlink": "get-started-with-programming",
"title": "Get started with programming!",
"body": "@@ -6023,16 +6023,35 @@\n acrity%5D(\n+https://blog.aas.sh\n /content\n@@ -15868,16 +15868,35 @@\n ntures%5D(\n+https://blog.aas.sh\n /content\n",
"json_metadata": "{\"tags\":[\"programming\",\"beginners\",\"guide\",\"how\",\"start\"],\"image\":[\"https://blog.aas.sh/content/2017-02/alacrity.gif\",\"https://blog.aas.sh/content/2017-04/vimadventures.gif\"],\"links\":[\"https://blog.aas.sh/posts/2017-04-11-Start-Programming/\",\"https://www.codecademy.com/\",\"https://cs50.harvard.edu/\",\"https://www.edx.org/course/introduction-computer-science-harvardx-cs50x\",\"https://www.codeavengers.com/\",\"http://github.com\",\"https://gitter.im/\",\"http://www.monogame.net/\",\"https://www.ubuntu.com/\",\"https://blog.aas.sh/Mistakes\",\"http://GitHub.com\",\"https://guides.github.com/activities/hello-world/\",\"https://education.github.com/pack\",\"https://vim-adventures.com/\",\"https://github.com/Crysikrend/emacs\",\"http://orgmode.org/\",\"http://brackets.io/\",\"https://atom.io/\",\"https://www.sublimetext.com/\",\"https://www.visualstudio.com/\",\"https://www.jetbrains.com/rider/\",\"https://www.unrealengine.com/\",\"http://reddit.com\",\"http://boards.4chan.org/g/\",\"discordapp.com\",\"https://discordapp.com/invite/gamedev\",\"https://discordapp.com/invite/wdg\",\"http://github.com/crysikrend/sprinty\",\"https://www.libsdl.org/\",\"http://BestInSlot.gg\",\"http://twitter.com/crysikrend\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}aas-shpublished a new post: haskell-for-beginners2018/08/26 17:41:51
aas-shpublished a new post: haskell-for-beginners
2018/08/26 17:41:51
| parent author | |
| parent permlink | programming |
| author | aas-sh |
| permlink | haskell-for-beginners |
| title | Haskell for beginners |
| body | > This post can be found on my blog [here.](https://blog.aas.sh/posts/2018-03-18-What-Even-Is-Haskell/) You may have noticed that I have been talking a lot about Haskell lately. In this post, I'd like to write a beginner-friendly summary in laymen's terms with regards to why I have taken such an interest in a language I've only started using. Hopefully this will inspire some people to consider using alternate languages to the ones they're used to. ## What is Haskell? >Taken from the [wiki](https://wiki.haskell.org/Introduction), *[Haskell](https://haskell.org) is a [polymorphic](https://wiki.haskell.org/Polymorphism), [statically typed](https://wiki.haskell.org/Typing), [lazy](https://wiki.haskell.org/Lazy_evaluation) and [purely-functional](https://wiki.haskell.org/Functional_programming) language*. Hopefully by the end of this post that sentence will be broken down bit by bit. One of the reasons I started wanting to learn Haskell was because people promised me that learning Haskell will improve your programming skills in general. For reasons we will go into, Haskell has a fairly steep learning curve but a huge payoff. As soon as you can get your head around it not only will you be able to produce elegant code in Haskell but also you will be thinking about new concepts that are important to functional programming that are also applicable to other languages. It's important to note that while Haskell is a purely functional language, ***some languages such as JavaScript are capable of being functional too***, so it would be good to understand FP even if you aren't going to use Haskell, as it may help you in a language you will use later. ### Functional programming Let's start with what functional programming actually is with a few examples. In essence, functional programming is a mind shift from [Imperative](https://en.wikipedia.org/wiki/Imperative_programming) programming (the one most people are used to), where additional emphasis is placed on the manipulation and transformation of data through functions. Someone who's more of an expert in Haskell or FP in general could give a better answer, but I'm rolling with this explanation for people like my past self. It can be hard to imagine the differences between the two when you haven't really used any functional languages, so just try to keep up and hopefully I can make this relatively painless. To explain what I mentioned above, I want to start talking about what we mean when we say 'function'. In mathematics, you can imagine the 'number machine' teaching methods they use early on. You place some numbers or some form of data inside the function, and it spits out different numbers or data. However, when you start learning programming you quickly forget this idea and instead imagine functions as a set of instructions - you are telling the computer to do something in an order in which operations are executed. There are loops, there are if statements, but at the end of the day there is some explicit instruction set that your program is following. The entirety of a game is within a loop that keeps going until the game closes - you pass in movement and every frame the character moves, the world reacts and finally the world is drawn. When we talk about imperative vs functional programming, forget concepts of [Object Oriented](https://en.wikipedia.org/wiki/Object-oriented_programming) and [Procedural](https://en.wikipedia.org/wiki/Procedural_programming) programming etc. We aren't talking about the ways of programming in a language, we're talking about the *type* of programming the language itself is capable of doing. They are independent and so you shouldn't dwell on them for this post. Just wanted to clear this up in case you then start questioning the differences between procedural and imperative when you usually do procedural programming inside an imperative language. Back on topic. Functional programming is an entirely different ball game. It's very difficult to translate imperative code into functional because of the way things are done. There's a wealth of information and discussion on the topic so I won't go into too much detail, but rather try to navigate the simplest aspects so that people who haven't given it a go can still understand it. Below is an example of imperative programming: ```cs // A class in C++ which will represent the player in the game: public class Player { int x = 0; int y = 0; // Function to move the player public void MovePlayer(int x, int y) { // Ensure that the player will always be in-bounds (0-1000) if (this.x + x > 1000) this.x = 1000; else if (this.x + x < 0) this.x = 0; else this.x += x; // Imagine the same for Y: // ... } } ``` So in this example, we have a very simple class `Player` which has a single function `MovePlayer`. This function returns absolutely nothing, it is a set of instructions detailing how the player will respond to some form of input. When we call the function like so: `MovePlayer(1, 2);` when the program has just started, we should expect the coordinates of the player to then be `(1, 2)` assuming that the rest of the function is completed. Calling it twice will move the player to `(2, 4)` and so forth. This is a simple example of [Object Oriented Programming](https://en.wikipedia.org/wiki/Object-oriented_programming) and is very effective whilst also being easy to read. When looking at `MovePlayer`, you start at the top and read it downwards - why wouldn't you? This feels natural and it actually looks like a list of instructions - you can role-play as the computer and do everything in your head step by step. When navigating `if` statements it's easy to see the flow of the function and which line is executed next. Time to bring in some FP. The fact that this function returns nothing (well, `Void`, as you can actually return `Nothing` in Haskell!) shows that this function 'does' something, it doesn't transform your data in any way, it just stores it away and accumulates it. The structure of this function doesn't exactly translate cleanly into a functional language at all. Only a few functions in Haskell 'do' things - think of it in a sense that one function will be impure that will use all the pure functions to get things done. With imperative programming, states can be found everywhere. There is a sense of 'state' for every instance of the player class as they each hold data that details where they are at any moment in time. In Haskell, without getting into advanced techniques, there's not really a sense of state anymore. We will go into what purity means in the next chapter, so we will ignore the sense of state (the `Player` class) and instead look at a function that `MovePlayer` function. ```hs -- A function in Haskell: calculateNewCoords :: (Int, Int) -> (Int, Int) -> (Int, Int) calculateNewCoords (x, y) (i, j) = (calc x i, calc y j) where calc a b | a + b > 1000 = 1000 | a + b < 0 = 0 | otherwise = a + b ``` Now for those who are unfamiliar with Haskell may feel a little scared over the code above. This can *definitely* be cleaned up to be more elegant, but I feel this version demonstrates quite a few features of Haskell. Firstly, we have defined almost a 'mini-function' called `calc`. We are no longer reading the function from top to bottom as in order to understand the second line we need to have read `calc` first. Haskell is very mathematics based, and so you need to imagine that you are writing a mathematical function rather than a set of instructions. In this case, we defined a function which investigates two vectors and adds their components together and ensure that they are within 0 and 1000. Obviously, if the bounds were to be any different, we either need to hard code them in (by replacing `1000` and `0`) or by passing them in. Secondly, let's address what the first line actually means. The first line is the type declaration of the function - in this case, we are passing in two tuples (pairs in this case) containing two `Int`s each, and then finally returning a tuple. As you can expect, this function takes a vector to represent ***a position*** and a vector in which to translate by. The parameters are split up by `->` where the last section is the return value. By following the rules we established in the previous example, this function should hopefully spit out another tuple of `Int`s where the position will eventually be. The reason I placed emphasis on the fact it is *a position* is because this function does not belong to any class or instance; anything can call it. Because of the fact that we pass in the position we are manipulating and also returning the result, we are able to call this a ***pure*** function that is completely free from side effects and does not depend on anything else to be called. If you are into [Parallel Computing](https://en.wikipedia.org/wiki/Parallel_computing), this is a very good thing as it means that two functions cannot touch the same data at the same time. Following from the previous point - the fact that you are always operating and returning data means that another strength of Haskell and other functional languages is that data is [immutable](https://en.wikipedia.org/wiki/Immutable_object); once data is created it cannot be changed. If you use data properly and wisely, this can lead to saving memory. It is also more secure - unless you overwrite your variable (which is usually done in `do` syntax, a bit out of scope of this blog), your data will always be the same. You don't usually overwrite data a lot in Haskell, but if you did it would be a lot like overwriting a variable passed by value where you are only messing with the copy. ### Pure functions Let's look into `Pure` functions closely. As described earlier, a pure function has no side effects. By side effect, we mean something which is done as a consequence of calling a function. This could be changing values that aren't a part of the function or simply using them. Here's an imperative example: ```cs // C# Example 1 - // This function can be called from anywhere: public int addem(int a, int b) { return a + b; } ``` That's a very simplistic function written in C#. It doesn't take much to realise that there isn't much of a point to this function when you can use `+` to make it completely redundant. Let's mix it up a bit. ```cs // C# Example 2 - // Imagine this is a function in some sort of class to store 'c': int c = 5; public int addem(int a, int b) { return a + b + c; } ``` So what's different between these two functions? Well, again, it doesn't require a high IQ to see that there's now an external variable named `c` which is going to be added to whatever we pass to our function. What's important to note here, is that passing in `a = 1` and `b = 2` may not always return `8` with this function so long as `c` is visible outside the function. This is where the word `pure` comes from: a pure function will ***always*** return the same outputs for the same set of given inputs. When doing functional programming, the majority of your functions will follow this pattern. You should be rubbing your head right now if you're a more involved programmer - how the hell do you ever get anything done? The answer is to divide your program into pure and impure parts. You begin to look at what computations actually require a sense of state and filter down your functionality into small, focused functions that only focus on manipulating data. When you wrap things up, you will likely have a few or even just one impure function that ties everything together. The key to FP is to really evaluate the purity of every function to ensure that you can have as many pure functions as possible. ### Laziness Now it's time to look into the other buzzwords that are tagged in Haskell's description. [Lazy Evaluation](https://wiki.haskell.org/Lazy_evaluation) means that you can actually utilise lists of infinite length without crashing the program. Haskell will only evaluate expressions when it needs to, so taking the 32132nd number from an infinite list only requires the list to be calculated to that point. Here's a few examples of some infinite lists written in different ways: ```hs -- Haskell time: -- This is a list of one through ten λ> [1..10] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -- The same list as above, but with a 'step' to make it odd only λ> [1,3..10] [1, 3, 5, 7, 9] -- This is a list like the first but doesn't stop at ten λ> [1..] -- Being able to create infinite lists easily like this simply relies -- on the 'Ord' typeclass. Basically, if you have a type that can be -- ordered, you can make infinite lists like we've shown here! -- Note that it doesn't exist until you actually use it λ> [1..] !! 5 5 λ> take 5 [1..] [1, 2, 3, 4, 5] -- A list like the second, but infinite λ> [1, 3..] -- Now when we use the lists λ> [1, 3..] !! 5 9 λ> take 10 [1, 3..] [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] -- Going down λ> take 10 [5, 4..] [5, 4, 3, 2, 1, 0, -1, -2, -3, -4] -- Creating an infinite list through recursion λ> let someList = 1 : map (+1) someList -- Every iteration prepends '1' and then maps (+1) onto every element in the list as follows: -- [1] -- 1 : [2] -- 1 : [2, 3] -- 1 : [2, 3, 4] -- Using the recursive endless loop will not break λ> take 5 someList [1, 2, 3, 4, 5] λ> take 5 [x*2 | x <- someList] [2, 4, 6, 8, 10] -- Try to work out how this infinite list is computed, what number is next? -- This is called 'List Comprehension' λ> take 12 [x*3 + y | x <- someList, y <- [10,9..7]] [13, 12, 11, 10, 16, 15, 14, 13, 19, 18, 17, 16] -- Here is a filter with list comprehension λ> take 5 [x | x <- [5, 6..], x `mod` 2 == 0] [6, 8, 10, 12, 14] -- Ready to get your mind blown? λ> take 5 [if x `mod` 2 == 0 then "EVEN!" else "ODD!" | x <- [1..]] ["ODD!","EVEN!","ODD!","EVEN!","ODD!"] -- Note that I've taken out the floating point errors here λ> take 5 [0, 0.1..] [0.1, 0.2, 0.3, 0.4, 0.5] λ> take 5 ['l'..] ['l', 'm', 'n', 'o', 'p'] -- Actually, in Haskell, a string is actually just a list of characters, so.. "lmnop" -- Note that the above example isn't constrained to the alphabet -- and will never loop back round to the alpha-numeric ascii characters -- Not to worry though! A function called cycle can loop a list infinitely! λ> ['A'..'Z'] "ABCDEFGHIJKLMNOPQRSTUVWXYZ" λ> let alphaBetty = cycle ['A'..'Z'] -- Now alphaBetty is a list of the alphabet cycling infinitely λ> take 6 (drop 23 alphaBetty) "XYZABC" -- Note that cycle doesn't require Ord at all, as it uses a pre-made list -- Also note, that [1..] is simply syntactic sugar for the method we used for -- 'someList' ``` I guess you could say I was pretty lazy in this area as I just demonstrated infinite lists rather than really talking about them, but who cares? ### Static Typing This subject isn't specific to Haskell, but I'll give you the run down anyway as you may not be clear on it in the first place. Essentially, in [Static Typing](https://wiki.haskell.org/Typing) the type of every variable is known at compile time. Usually, this means that the programmer must explicitly say what type a variable is before you can use it. This is obvious in C++: ```cpp // C++: int sum; int number = 0; sum = number + 1; ``` In Haskell, there's something called 'type inference' which means that you don't necessarily have to define all of your variable types because the language is very smart. You should still explicitly label your functions though to make sure the compiler is on the same stage as yourself. C++ and Haskell are both statically typed languages, including (but not exclusive to) Java, C and Scala. So what is *dynamic typing*? Well, it is the opposite of static typing. JavaScript and Python (a language I am unfamiliar with) are both examples of dynamically typed languages. You don't have to write out that your variable is an `Int`, for instance. Remember that some statically typed languages are capable of this, but that's just the compiler being clever and doing the work for you. People say JS is 'untyped', but I'm just going to call it dynamic typing as it is most definitely not static. Now, at the risk of confusing you, I'm going to talk about dynamic typing with regards to [Strong and Weak typing](https://en.wikipedia.org/wiki/Strong_and_weak_typing). These are two different concepts and so you shouldn't get mixed up between them - just because a language is dynamically typed doesn't necessarily mean it's strong (or weak) typed. If you are working with a strongly typed language, then once you have bound a variable to a type then you must ensure that it is always that type. For instance, does concatenating (joining) a `String` with an `Int` work? Does `"High " + 5` compile somehow? If it does, is there an explicit method for it, or is it a feature of your language that allows types to mingle like this? A weakly typed language will easily allow it, resulting in `"High 5"`. This is a really simple example and isn't so important, but it's hard to talk about dynamic typing without mentioning it. ### Polymorphism No, it's not the [spell in World of Warcraft](http://www.wowhead.com/spell=118/polymorph), however, the meaning behind the two go together. Essentially, [Polymorphism](https://wiki.haskell.org/Polymorphism) allows a variable to have more than one type. Once the type is bound then it must remain consistent through every call to said variable or parameter, but until that point it can be anything you like within reason. Haskell has multiple ways to do this, the first is very simple to demonstrate. If you have ever heard of an identity function, then this will quickly make sense: ```hs -- Haskell's identity function: id :: a -> a ``` Note that in Haskell, we read `::` as '*has type of*' as in '*The function `id` has a type of `a -> a`*'. This isn't really saying what the function actually does, however, given the type, there's not a lot it *could* do. So what is `a`? Well, we don't know - it's ***polymorphic***. Since we have no idea what it actually is or what it could be, we can't really pass it to any functions *unless* the function also takes a parameter of `a`, meaning that it accepts anything. `a -> a` means that this function will take a variable of any type and will return a variable *of the same type*. If you aren't sure what an identity function is, it is simply a function that, in context, does nothing to it's arguments. `1` is the identity for multiplication and division because anything `*1` or `/1` equals itself - `x * 1 = x`. In addition (and subtraction), `0` is the identity because `x + 0 = x`. In this case, `id` is an identity function which does nothing to it's parameters and simply returns them. It might not make sense now, but it does have it's uses. Anyway, `id` is a polymorphic function because it accepts literally ***any*** type. It doesn't need any information on what the thing it accepts is - it could be a list or even another function - that's for another blog post ;). The function will always return something of the same type and will be bound as soon as you pass in a parameter. Here's an example: ```hs -- Usage of id in Haskell: λ> id 1 1 -- The type of that first id call was Int -> Int -- ... or was it? We'll get onto that next! λ> id "hello" "hello" -- The type of id here was [Char] -> [Char], or String -> String -- as string is essentially an alias of [char] λ> id ['A', 'B', 'C'] "ABC" -- This third call is exactly the same as the example above, -- Haskell prefers to specify that it's a [Char], but then -- writes it as a string to be friendly to read for us, thanks HS! λ> id [(1, "Hello"), (2, "there"), (3, "mate!")] [(1, "Hello"), (2, "there"), (3, "mate!")] -- The type of id here in the fourth call was -- [(Int, [Char])] -> [(Int, [Char])] -- Again, not really Int, but that's coming up next ``` As we went through before, the `->` symbol separates the parameters from each other, where the last one on the line is the return value. The type of `id` binds itself to whatever variable type we pass in. It is also important to remember that `a` is just easy to use as it's the first letter of the alphabet, but the name doesn't matter. Types start with an uppercase letter, such as `Int`, `Bool`, `Char` or `String`. Anything lowercase can be seen as a variable of any type. `a -> b` means we have a function returning something that ***could*** be a different type to the one we passed in. `a -> b -> c` means that we pass in two parameters that aren't necessarily the same type, and get back another type that could be different, or the same as `a` or `b`. Remember, these letters could be *anything*. Just because `a` and `b` indicate that there are uses of two independent types in our function doesn't mean that they *have* to be different, just that they *could* be. So what was I going on about, surely that first call was `Int -> Int`, I nailed that Ashley! I had it guessed! Well, in this case, you are actually a bit too specific. It's time to introduce `=>` in the context of type declarations. ```hs --Haskell identity function again: λ> id 1 1 λ>:t id 1 Num a => a ``` So when we use Haskell in a terminal to evaluate expressions we can use `:t` to query the type of something. This is querying the type of the *result* of `id 1`, so don't get confused. Our answer was `Num a => a`, which is a little different to what I've shown so far. `=>` describes the thing on the right with the definitions on the left - it's saying that the `a` after the arrow is deriving the typeclass `Num`. As I was saying, we asked for the *result* of the function, and so our compiler is telling us that the result is `a`, where `a is part of the Num` typeclass. Therefore, the specialised type of our function `id` *before the function was applied* became as follows: ```hs Num a => a -> a ``` You can still see the original `a -> a` type declaration coming through, but now we know that the `a` sent in and `a` retrieved, which are both the same type, are now a `Num`. What is `Num`? The second way Haskell is polymorphic is less generic than the previous. As you get more specific, you get more functionality at a cost of being general - it makes sense really, as you can't attach functionality to something without defining some basic principles to manipulate. Enter `Num`, a typeclass for a number. When something derives `Num`, we mean that whatever the type is it has to have some core functions. Put it this way, when you derive `Num`, you have to then fill in some functions for your type showing how they operate - if you make some whacky type that derives `Num`, you need to work out how things like `+`, `-` and `*` work (you can research why you don't define `/`). [The functions can be found here on Hackage](http://hackage.haskell.org/package/base-4.11.0.0/docs/Prelude.html#t:Num) - just make sure you let the page load and scroll to the `Num` section or you'll get confused. Let's have a look at the functions from that page: ```hs -- Haskell Num functions: λ> :t (+) (+) :: Num a => a -> a -> a -- If you have followed everything so far, you should -- be able to see that addition takes two Nums and returns a Num λ> :t (*) (*) :: Num a => a -> a -> a -- Remember, we are working with Num here, not Int -- We don't know how this function is implemented, just that types -- like Int are compatible with these functions. λ> :t abs abs :: Num a => a -> a -- Note that here we only have one parameter and one return value -- that's because getting the absolute value simply makes the number positive -- and it doesn't need any other parameters to operate -- Let's query what typeclasses Int actually derives, so you can see how much Int can do! λ> :i Int data Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types' instance Bounded Int -- Defined in `GHC.Enum' instance Enum Int -- Defined in `GHC.Enum' instance Eq Int -- Defined in `GHC.Classes' instance Integral Int -- Defined in `GHC.Real' instance Num Int -- Defined in `GHC.Num' instance Ord Int -- Defined in `GHC.Classes' instance Read Int -- Defined in `GHC.Read' instance Real Int -- Defined in `GHC.Real' instance Show Int -- Defined in `GHC.Show' ``` As you can see from that last demonstration, `Int` actually has a lot of functionality! If we have a function that has a declaration such as `Eq a => a -> a -> Bool`, we can start thinking about the types of things it could do. `Eq` is the typeclass of equality - in terms of checking if things are equal. If we have a function which takes two variables of the same type that have the ability to be compared to see if they are equal or not, we can see how we would get a `Bool` out of this (where `Bool` is either `True` or `False`). This function would still be polymorphic as we don't know what type we are being given, all we know is that they can be compared. It isn't 100% generic, but neither is it 100% specific, therefore qualifying as polymorphic. You may already know how your current language implements polymorphism, whether it is through inheritance of other classes or some other method. This is simply how Haskell does it, and it is very, ***very*** powerful. ## Wrapping things up I hope this little adventure has been a fun read and that I actually convince some of you to dive into Haskell a little bit. Learning Haskell has been a huge help to my challenge-craving brain and I am in love with how mathematical everything is. If you are interested to start learning, take a look at [Learn you a Haskell for a Great Good (LYAH)](http://learnyouahaskell.com/) which is free, or the [Haskellbook](http://haskellbook.com/) which is more thorough, more complex and more expensive. If you want to get serious, go for the [Haskellbook](http://haskellbook.com/), but I would advise that you have a look at [LYAH](http://learnyouahaskell.com/) first for a quick overview of what you can do. It'll get you up and running to the point of playing around with code, but the more academic of you will probably need something more. If you want something else too look at, go and take a look at [ComputerPhile on YouTube](https://www.youtube.com/channel/UC9-y-6csu5WGm29I7JiwpnA), they've done some great videos on not just Haskell and not just on Functional Programming, but on computing in general. Definitely check out the Haskell videos though. If you need some help getting started (or even when you're an expert!) or want to talk to some Haskell pros, go to the [#Haskell IRC on Freenode](http://webchat.freenode.net/?channels=haskell) or the [Functional Programming Discord Server](https://discord.me/fp). Lastly, give me a [follow](https://twitter.com/crysikrend) and a tweet if this has helped. I am doing my best to share what I know to like-minded people who hunger for academia. # Thanks for reading, this was really fun to write! |
| json metadata | {"tags":["programming","beginners","haskell","how","start"],"links":["https://blog.aas.sh/posts/2018-03-18-What-Even-Is-Haskell/","https://wiki.haskell.org/Introduction","https://haskell.org","https://wiki.haskell.org/Polymorphism","https://wiki.haskell.org/Typing","https://wiki.haskell.org/Lazy_evaluation","https://wiki.haskell.org/Functional_programming","https://en.wikipedia.org/wiki/Imperative_programming","https://en.wikipedia.org/wiki/Object-oriented_programming","https://en.wikipedia.org/wiki/Procedural_programming","https://en.wikipedia.org/wiki/Parallel_computing","https://en.wikipedia.org/wiki/Immutable_object","https://en.wikipedia.org/wiki/Strong_and_weak_typing","http://www.wowhead.com/spell=118/polymorph","http://hackage.haskell.org/package/base-4.11.0.0/docs/Prelude.html#t:Num","http://learnyouahaskell.com/","http://haskellbook.com/","https://www.youtube.com/channel/UC9-y-6csu5WGm29I7JiwpnA","http://webchat.freenode.net/?channels=haskell","https://discord.me/fp","https://twitter.com/crysikrend"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25412012/Trx d43829d662329d072d73dad75d582ea69f856acc |
View Raw JSON Data
{
"trx_id": "d43829d662329d072d73dad75d582ea69f856acc",
"block": 25412012,
"trx_in_block": 3,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:41:51",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "programming",
"author": "aas-sh",
"permlink": "haskell-for-beginners",
"title": "Haskell for beginners",
"body": "> This post can be found on my blog [here.](https://blog.aas.sh/posts/2018-03-18-What-Even-Is-Haskell/)\n\nYou may have noticed that I have been talking a lot about Haskell lately. In this post, I'd like to write a beginner-friendly summary in laymen's terms with regards to why I have taken such an interest in a language I've only started using. Hopefully this will inspire some people to consider using alternate languages to the ones they're used to.\n\n## What is Haskell?\n>Taken from the [wiki](https://wiki.haskell.org/Introduction), *[Haskell](https://haskell.org) is a [polymorphic](https://wiki.haskell.org/Polymorphism), [statically typed](https://wiki.haskell.org/Typing), [lazy](https://wiki.haskell.org/Lazy_evaluation) and [purely-functional](https://wiki.haskell.org/Functional_programming) language*.\n\nHopefully by the end of this post that sentence will be broken down bit by bit. One of the reasons I started wanting to learn Haskell was because people promised me that learning Haskell will improve your programming skills in general. For reasons we will go into, Haskell has a fairly steep learning curve but a huge payoff. As soon as you can get your head around it not only will you be able to produce elegant code in Haskell but also you will be thinking about new concepts that are important to functional programming that are also applicable to other languages. It's important to note that while Haskell is a purely functional language, ***some languages such as JavaScript are capable of being functional too***, so it would be good to understand FP even if you aren't going to use Haskell, as it may help you in a language you will use later.\n\n### Functional programming\nLet's start with what functional programming actually is with a few examples. In essence, functional programming is a mind shift from [Imperative](https://en.wikipedia.org/wiki/Imperative_programming) programming (the one most people are used to), where additional emphasis is placed on the manipulation and transformation of data through functions. Someone who's more of an expert in Haskell or FP in general could give a better answer, but I'm rolling with this explanation for people like my past self. It can be hard to imagine the differences between the two when you haven't really used any functional languages, so just try to keep up and hopefully I can make this relatively painless.\n\nTo explain what I mentioned above, I want to start talking about what we mean when we say 'function'. In mathematics, you can imagine the 'number machine' teaching methods they use early on. You place some numbers or some form of data inside the function, and it spits out different numbers or data. However, when you start learning programming you quickly forget this idea and instead imagine functions as a set of instructions - you are telling the computer to do something in an order in which operations are executed. There are loops, there are if statements, but at the end of the day there is some explicit instruction set that your program is following. The entirety of a game is within a loop that keeps going until the game closes - you pass in movement and every frame the character moves, the world reacts and finally the world is drawn.\n\nWhen we talk about imperative vs functional programming, forget concepts of [Object Oriented](https://en.wikipedia.org/wiki/Object-oriented_programming) and [Procedural](https://en.wikipedia.org/wiki/Procedural_programming) programming etc. We aren't talking about the ways of programming in a language, we're talking about the *type* of programming the language itself is capable of doing. They are independent and so you shouldn't dwell on them for this post. Just wanted to clear this up in case you then start questioning the differences between procedural and imperative when you usually do procedural programming inside an imperative language.\n\nBack on topic. Functional programming is an entirely different ball game. It's very difficult to translate imperative code into functional because of the way things are done. There's a wealth of information and discussion on the topic so I won't go into too much detail, but rather try to navigate the simplest aspects so that people who haven't given it a go can still understand it. Below is an example of imperative programming:\n\n```cs\n// A class in C++ which will represent the player in the game:\npublic class Player {\n int x = 0;\n int y = 0;\n\n // Function to move the player\n public void MovePlayer(int x, int y) {\n // Ensure that the player will always be in-bounds (0-1000)\n if (this.x + x > 1000)\n this.x = 1000;\n else if (this.x + x < 0)\n this.x = 0;\n else\n this.x += x;\n\n // Imagine the same for Y:\n // ...\n }\n}\n```\n\nSo in this example, we have a very simple class `Player` which has a single function `MovePlayer`. This function returns absolutely nothing, it is a set of instructions detailing how the player will respond to some form of input. When we call the function like so: `MovePlayer(1, 2);` when the program has just started, we should expect the coordinates of the player to then be `(1, 2)` assuming that the rest of the function is completed. Calling it twice will move the player to `(2, 4)` and so forth. This is a simple example of [Object Oriented Programming](https://en.wikipedia.org/wiki/Object-oriented_programming) and is very effective whilst also being easy to read.\n\nWhen looking at `MovePlayer`, you start at the top and read it downwards - why wouldn't you? This feels natural and it actually looks like a list of instructions - you can role-play as the computer and do everything in your head step by step. When navigating `if` statements it's easy to see the flow of the function and which line is executed next.\n\nTime to bring in some FP. The fact that this function returns nothing (well, `Void`, as you can actually return `Nothing` in Haskell!) shows that this function 'does' something, it doesn't transform your data in any way, it just stores it away and accumulates it. The structure of this function doesn't exactly translate cleanly into a functional language at all. Only a few functions in Haskell 'do' things - think of it in a sense that one function will be impure that will use all the pure functions to get things done.\n\nWith imperative programming, states can be found everywhere. There is a sense of 'state' for every instance of the player class as they each hold data that details where they are at any moment in time. In Haskell, without getting into advanced techniques, there's not really a sense of state anymore. We will go into what purity means in the next chapter, so we will ignore the sense of state (the `Player` class) and instead look at a function that `MovePlayer` function.\n\n```hs\n-- A function in Haskell:\ncalculateNewCoords :: (Int, Int) -> (Int, Int) -> (Int, Int)\ncalculateNewCoords (x, y) (i, j) = (calc x i, calc y j)\n where calc a b\n | a + b > 1000 = 1000\n | a + b < 0 = 0\n | otherwise = a + b\n```\n\nNow for those who are unfamiliar with Haskell may feel a little scared over the code above. This can *definitely* be cleaned up to be more elegant, but I feel this version demonstrates quite a few features of Haskell. Firstly, we have defined almost a 'mini-function' called `calc`. We are no longer reading the function from top to bottom as in order to understand the second line we need to have read `calc` first. Haskell is very mathematics based, and so you need to imagine that you are writing a mathematical function rather than a set of instructions. In this case, we defined a function which investigates two vectors and adds their components together and ensure that they are within 0 and 1000. Obviously, if the bounds were to be any different, we either need to hard code them in (by replacing `1000` and `0`) or by passing them in.\n\nSecondly, let's address what the first line actually means. The first line is the type declaration of the function - in this case, we are passing in two tuples (pairs in this case) containing two `Int`s each, and then finally returning a tuple. As you can expect, this function takes a vector to represent ***a position*** and a vector in which to translate by. The parameters are split up by `->` where the last section is the return value. By following the rules we established in the previous example, this function should hopefully spit out another tuple of `Int`s where the position will eventually be. The reason I placed emphasis on the fact it is *a position* is because this function does not belong to any class or instance; anything can call it. Because of the fact that we pass in the position we are manipulating and also returning the result, we are able to call this a ***pure*** function that is completely free from side effects and does not depend on anything else to be called. If you are into [Parallel Computing](https://en.wikipedia.org/wiki/Parallel_computing), this is a very good thing as it means that two functions cannot touch the same data at the same time.\n\nFollowing from the previous point - the fact that you are always operating and returning data means that another strength of Haskell and other functional languages is that data is [immutable](https://en.wikipedia.org/wiki/Immutable_object); once data is created it cannot be changed. If you use data properly and wisely, this can lead to saving memory. It is also more secure - unless you overwrite your variable (which is usually done in `do` syntax, a bit out of scope of this blog), your data will always be the same. You don't usually overwrite data a lot in Haskell, but if you did it would be a lot like overwriting a variable passed by value where you are only messing with the copy.\n\n### Pure functions\nLet's look into `Pure` functions closely. As described earlier, a pure function has no side effects. By side effect, we mean something which is done as a consequence of calling a function. This could be changing values that aren't a part of the function or simply using them. Here's an imperative example:\n\n```cs\n// C# Example 1 -\n// This function can be called from anywhere:\npublic int addem(int a, int b) {\n return a + b;\n}\n```\n\nThat's a very simplistic function written in C#. It doesn't take much to realise that there isn't much of a point to this function when you can use `+` to make it completely redundant. Let's mix it up a bit.\n\n```cs\n// C# Example 2 -\n// Imagine this is a function in some sort of class to store 'c':\nint c = 5;\npublic int addem(int a, int b) {\n return a + b + c;\n}\n```\n\nSo what's different between these two functions? Well, again, it doesn't require a high IQ to see that there's now an external variable named `c` which is going to be added to whatever we pass to our function. What's important to note here, is that passing in `a = 1` and `b = 2` may not always return `8` with this function so long as `c` is visible outside the function. This is where the word `pure` comes from: a pure function will ***always*** return the same outputs for the same set of given inputs. When doing functional programming, the majority of your functions will follow this pattern. You should be rubbing your head right now if you're a more involved programmer - how the hell do you ever get anything done?\n\nThe answer is to divide your program into pure and impure parts. You begin to look at what computations actually require a sense of state and filter down your functionality into small, focused functions that only focus on manipulating data. When you wrap things up, you will likely have a few or even just one impure function that ties everything together. The key to FP is to really evaluate the purity of every function to ensure that you can have as many pure functions as possible.\n\n### Laziness\nNow it's time to look into the other buzzwords that are tagged in Haskell's description. [Lazy Evaluation](https://wiki.haskell.org/Lazy_evaluation) means that you can actually utilise lists of infinite length without crashing the program. Haskell will only evaluate expressions when it needs to, so taking the 32132nd number from an infinite list only requires the list to be calculated to that point. Here's a few examples of some infinite lists written in different ways:\n\n```hs\n-- Haskell time:\n-- This is a list of one through ten\nλ> [1..10]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n-- The same list as above, but with a 'step' to make it odd only\nλ> [1,3..10]\n[1, 3, 5, 7, 9]\n\n-- This is a list like the first but doesn't stop at ten\nλ> [1..]\n\n-- Being able to create infinite lists easily like this simply relies\n-- on the 'Ord' typeclass. Basically, if you have a type that can be\n-- ordered, you can make infinite lists like we've shown here!\n\n-- Note that it doesn't exist until you actually use it\nλ> [1..] !! 5\n5\nλ> take 5 [1..]\n[1, 2, 3, 4, 5]\n\n-- A list like the second, but infinite\nλ> [1, 3..]\n\n-- Now when we use the lists\nλ> [1, 3..] !! 5\n9\nλ> take 10 [1, 3..]\n[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]\n\n-- Going down\nλ> take 10 [5, 4..]\n[5, 4, 3, 2, 1, 0, -1, -2, -3, -4]\n\n-- Creating an infinite list through recursion\nλ> let someList = 1 : map (+1) someList\n-- Every iteration prepends '1' and then maps (+1) onto every element in the list as follows:\n-- [1]\n-- 1 : [2]\n-- 1 : [2, 3]\n-- 1 : [2, 3, 4]\n\n-- Using the recursive endless loop will not break\nλ> take 5 someList\n[1, 2, 3, 4, 5]\nλ> take 5 [x*2 | x <- someList]\n[2, 4, 6, 8, 10]\n\n-- Try to work out how this infinite list is computed, what number is next?\n-- This is called 'List Comprehension'\nλ> take 12 [x*3 + y | x <- someList, y <- [10,9..7]]\n[13, 12, 11, 10, 16, 15, 14, 13, 19, 18, 17, 16]\n\n-- Here is a filter with list comprehension\nλ> take 5 [x | x <- [5, 6..], x `mod` 2 == 0]\n[6, 8, 10, 12, 14]\n\n-- Ready to get your mind blown?\nλ> take 5 [if x `mod` 2 == 0 then \"EVEN!\" else \"ODD!\" | x <- [1..]]\n[\"ODD!\",\"EVEN!\",\"ODD!\",\"EVEN!\",\"ODD!\"]\n\n-- Note that I've taken out the floating point errors here\nλ> take 5 [0, 0.1..]\n[0.1, 0.2, 0.3, 0.4, 0.5]\n\nλ> take 5 ['l'..]\n['l', 'm', 'n', 'o', 'p']\n-- Actually, in Haskell, a string is actually just a list of characters, so..\n\"lmnop\"\n\n-- Note that the above example isn't constrained to the alphabet\n-- and will never loop back round to the alpha-numeric ascii characters\n-- Not to worry though! A function called cycle can loop a list infinitely!\nλ> ['A'..'Z']\n\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\nλ> let alphaBetty = cycle ['A'..'Z']\n-- Now alphaBetty is a list of the alphabet cycling infinitely\nλ> take 6 (drop 23 alphaBetty)\n\"XYZABC\"\n\n-- Note that cycle doesn't require Ord at all, as it uses a pre-made list\n\n-- Also note, that [1..] is simply syntactic sugar for the method we used for\n-- 'someList'\n```\n\nI guess you could say I was pretty lazy in this area as I just demonstrated infinite lists rather than really talking about them, but who cares?\n\n### Static Typing\nThis subject isn't specific to Haskell, but I'll give you the run down anyway as you may not be clear on it in the first place. Essentially, in [Static Typing](https://wiki.haskell.org/Typing) the type of every variable is known at compile time. Usually, this means that the programmer must explicitly say what type a variable is before you can use it. This is obvious in C++:\n\n```cpp\n// C++:\nint sum;\nint number = 0;\nsum = number + 1;\n```\n\nIn Haskell, there's something called 'type inference' which means that you don't necessarily have to define all of your variable types because the language is very smart. You should still explicitly label your functions though to make sure the compiler is on the same stage as yourself. C++ and Haskell are both statically typed languages, including (but not exclusive to) Java, C and Scala.\n\nSo what is *dynamic typing*? Well, it is the opposite of static typing. JavaScript and Python (a language I am unfamiliar with) are both examples of dynamically typed languages. You don't have to write out that your variable is an `Int`, for instance. Remember that some statically typed languages are capable of this, but that's just the compiler being clever and doing the work for you. People say JS is 'untyped', but I'm just going to call it dynamic typing as it is most definitely not static. Now, at the risk of confusing you, I'm going to talk about dynamic typing with regards to [Strong and Weak typing](https://en.wikipedia.org/wiki/Strong_and_weak_typing). These are two different concepts and so you shouldn't get mixed up between them - just because a language is dynamically typed doesn't necessarily mean it's strong (or weak) typed.\n\nIf you are working with a strongly typed language, then once you have bound a variable to a type then you must ensure that it is always that type. For instance, does concatenating (joining) a `String` with an `Int` work? Does `\"High \" + 5` compile somehow? If it does, is there an explicit method for it, or is it a feature of your language that allows types to mingle like this? A weakly typed language will easily allow it, resulting in `\"High 5\"`. This is a really simple example and isn't so important, but it's hard to talk about dynamic typing without mentioning it.\n\n### Polymorphism\nNo, it's not the [spell in World of Warcraft](http://www.wowhead.com/spell=118/polymorph), however, the meaning behind the two go together. Essentially, [Polymorphism](https://wiki.haskell.org/Polymorphism) allows a variable to have more than one type. Once the type is bound then it must remain consistent through every call to said variable or parameter, but until that point it can be anything you like within reason. Haskell has multiple ways to do this, the first is very simple to demonstrate. If you have ever heard of an identity function, then this will quickly make sense:\n\n```hs\n-- Haskell's identity function:\nid :: a -> a\n```\n\nNote that in Haskell, we read `::` as '*has type of*' as in '*The function `id` has a type of `a -> a`*'. This isn't really saying what the function actually does, however, given the type, there's not a lot it *could* do. So what is `a`? Well, we don't know - it's ***polymorphic***. Since we have no idea what it actually is or what it could be, we can't really pass it to any functions *unless* the function also takes a parameter of `a`, meaning that it accepts anything. `a -> a` means that this function will take a variable of any type and will return a variable *of the same type*. If you aren't sure what an identity function is, it is simply a function that, in context, does nothing to it's arguments. `1` is the identity for multiplication and division because anything `*1` or `/1` equals itself - `x * 1 = x`. In addition (and subtraction), `0` is the identity because `x + 0 = x`. In this case, `id` is an identity function which does nothing to it's parameters and simply returns them. It might not make sense now, but it does have it's uses.\n\nAnyway, `id` is a polymorphic function because it accepts literally ***any*** type. It doesn't need any information on what the thing it accepts is - it could be a list or even another function - that's for another blog post ;). The function will always return something of the same type and will be bound as soon as you pass in a parameter. Here's an example:\n\n```hs\n-- Usage of id in Haskell:\nλ> id 1\n1\n\n-- The type of that first id call was Int -> Int\n-- ... or was it? We'll get onto that next!\n\nλ> id \"hello\"\n\"hello\"\n\n-- The type of id here was [Char] -> [Char], or String -> String\n-- as string is essentially an alias of [char]\n\nλ> id ['A', 'B', 'C']\n\"ABC\"\n\n-- This third call is exactly the same as the example above,\n-- Haskell prefers to specify that it's a [Char], but then\n-- writes it as a string to be friendly to read for us, thanks HS!\n\nλ> id [(1, \"Hello\"), (2, \"there\"), (3, \"mate!\")]\n[(1, \"Hello\"), (2, \"there\"), (3, \"mate!\")]\n\n-- The type of id here in the fourth call was\n-- [(Int, [Char])] -> [(Int, [Char])]\n-- Again, not really Int, but that's coming up next\n```\n\nAs we went through before, the `->` symbol separates the parameters from each other, where the last one on the line is the return value. The type of `id` binds itself to whatever variable type we pass in. It is also important to remember that `a` is just easy to use as it's the first letter of the alphabet, but the name doesn't matter. Types start with an uppercase letter, such as `Int`, `Bool`, `Char` or `String`. Anything lowercase can be seen as a variable of any type. `a -> b` means we have a function returning something that ***could*** be a different type to the one we passed in. `a -> b -> c` means that we pass in two parameters that aren't necessarily the same type, and get back another type that could be different, or the same as `a` or `b`. Remember, these letters could be *anything*. Just because `a` and `b` indicate that there are uses of two independent types in our function doesn't mean that they *have* to be different, just that they *could* be.\n\nSo what was I going on about, surely that first call was `Int -> Int`, I nailed that Ashley! I had it guessed! Well, in this case, you are actually a bit too specific. It's time to introduce `=>` in the context of type declarations.\n\n```hs\n--Haskell identity function again:\nλ> id 1\n1\nλ>:t id 1\nNum a => a\n```\n\nSo when we use Haskell in a terminal to evaluate expressions we can use `:t` to query the type of something. This is querying the type of the *result* of `id 1`, so don't get confused. Our answer was `Num a => a`, which is a little different to what I've shown so far. `=>` describes the thing on the right with the definitions on the left - it's saying that the `a` after the arrow is deriving the typeclass `Num`. As I was saying, we asked for the *result* of the function, and so our compiler is telling us that the result is `a`, where `a is part of the Num` typeclass. Therefore, the specialised type of our function `id` *before the function was applied* became as follows:\n\n```hs\nNum a => a -> a\n```\n\nYou can still see the original `a -> a` type declaration coming through, but now we know that the `a` sent in and `a` retrieved, which are both the same type, are now a `Num`. What is `Num`? The second way Haskell is polymorphic is less generic than the previous. As you get more specific, you get more functionality at a cost of being general - it makes sense really, as you can't attach functionality to something without defining some basic principles to manipulate.\n\nEnter `Num`, a typeclass for a number. When something derives `Num`, we mean that whatever the type is it has to have some core functions. Put it this way, when you derive `Num`, you have to then fill in some functions for your type showing how they operate - if you make some whacky type that derives `Num`, you need to work out how things like `+`, `-` and `*` work (you can research why you don't define `/`). [The functions can be found here on Hackage](http://hackage.haskell.org/package/base-4.11.0.0/docs/Prelude.html#t:Num) - just make sure you let the page load and scroll to the `Num` section or you'll get confused. Let's have a look at the functions from that page:\n\n```hs\n-- Haskell Num functions:\nλ> :t (+)\n(+) :: Num a => a -> a -> a\n-- If you have followed everything so far, you should\n-- be able to see that addition takes two Nums and returns a Num\n\nλ> :t (*)\n(*) :: Num a => a -> a -> a\n-- Remember, we are working with Num here, not Int\n-- We don't know how this function is implemented, just that types\n-- like Int are compatible with these functions.\n\nλ> :t abs\nabs :: Num a => a -> a\n-- Note that here we only have one parameter and one return value\n-- that's because getting the absolute value simply makes the number positive\n-- and it doesn't need any other parameters to operate\n\n-- Let's query what typeclasses Int actually derives, so you can see how much Int can do!\nλ> :i Int\ndata Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types'\ninstance Bounded Int -- Defined in `GHC.Enum'\ninstance Enum Int -- Defined in `GHC.Enum'\ninstance Eq Int -- Defined in `GHC.Classes'\ninstance Integral Int -- Defined in `GHC.Real'\ninstance Num Int -- Defined in `GHC.Num'\ninstance Ord Int -- Defined in `GHC.Classes'\ninstance Read Int -- Defined in `GHC.Read'\ninstance Real Int -- Defined in `GHC.Real'\ninstance Show Int -- Defined in `GHC.Show'\n```\n\nAs you can see from that last demonstration, `Int` actually has a lot of functionality! If we have a function that has a declaration such as `Eq a => a -> a -> Bool`, we can start thinking about the types of things it could do. `Eq` is the typeclass of equality - in terms of checking if things are equal. If we have a function which takes two variables of the same type that have the ability to be compared to see if they are equal or not, we can see how we would get a `Bool` out of this (where `Bool` is either `True` or `False`). This function would still be polymorphic as we don't know what type we are being given, all we know is that they can be compared. It isn't 100% generic, but neither is it 100% specific, therefore qualifying as polymorphic.\n\nYou may already know how your current language implements polymorphism, whether it is through inheritance of other classes or some other method. This is simply how Haskell does it, and it is very, ***very*** powerful.\n\n## Wrapping things up\nI hope this little adventure has been a fun read and that I actually convince some of you to dive into Haskell a little bit. Learning Haskell has been a huge help to my challenge-craving brain and I am in love with how mathematical everything is. If you are interested to start learning, take a look at [Learn you a Haskell for a Great Good (LYAH)](http://learnyouahaskell.com/) which is free, or the [Haskellbook](http://haskellbook.com/) which is more thorough, more complex and more expensive. If you want to get serious, go for the [Haskellbook](http://haskellbook.com/), but I would advise that you have a look at [LYAH](http://learnyouahaskell.com/) first for a quick overview of what you can do. It'll get you up and running to the point of playing around with code, but the more academic of you will probably need something more.\n\nIf you want something else too look at, go and take a look at [ComputerPhile on YouTube](https://www.youtube.com/channel/UC9-y-6csu5WGm29I7JiwpnA), they've done some great videos on not just Haskell and not just on Functional Programming, but on computing in general. Definitely check out the Haskell videos though. If you need some help getting started (or even when you're an expert!) or want to talk to some Haskell pros, go to the [#Haskell IRC on Freenode](http://webchat.freenode.net/?channels=haskell) or the [Functional Programming Discord Server](https://discord.me/fp).\n\nLastly, give me a [follow](https://twitter.com/crysikrend) and a tweet if this has helped. I am doing my best to share what I know to like-minded people who hunger for academia.\n\n# Thanks for reading, this was really fun to write!",
"json_metadata": "{\"tags\":[\"programming\",\"beginners\",\"haskell\",\"how\",\"start\"],\"links\":[\"https://blog.aas.sh/posts/2018-03-18-What-Even-Is-Haskell/\",\"https://wiki.haskell.org/Introduction\",\"https://haskell.org\",\"https://wiki.haskell.org/Polymorphism\",\"https://wiki.haskell.org/Typing\",\"https://wiki.haskell.org/Lazy_evaluation\",\"https://wiki.haskell.org/Functional_programming\",\"https://en.wikipedia.org/wiki/Imperative_programming\",\"https://en.wikipedia.org/wiki/Object-oriented_programming\",\"https://en.wikipedia.org/wiki/Procedural_programming\",\"https://en.wikipedia.org/wiki/Parallel_computing\",\"https://en.wikipedia.org/wiki/Immutable_object\",\"https://en.wikipedia.org/wiki/Strong_and_weak_typing\",\"http://www.wowhead.com/spell=118/polymorph\",\"http://hackage.haskell.org/package/base-4.11.0.0/docs/Prelude.html#t:Num\",\"http://learnyouahaskell.com/\",\"http://haskellbook.com/\",\"https://www.youtube.com/channel/UC9-y-6csu5WGm29I7JiwpnA\",\"http://webchat.freenode.net/?channels=haskell\",\"https://discord.me/fp\",\"https://twitter.com/crysikrend\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}aas-shpublished a new post: get-started-with-programming2018/08/26 17:33:48
aas-shpublished a new post: get-started-with-programming
2018/08/26 17:33:48
| parent author | |
| parent permlink | programming |
| author | aas-sh |
| permlink | get-started-with-programming |
| title | Get started with programming! |
| body | > This post can be found on my blog [here.](https://blog.aas.sh/posts/2017-04-11-Start-Programming/) It took me a while to figure my way around Steemit so I apologise for the deleted blogs! So you've been using the internet competently for many years of your life and you've become interested in programming - great! However, you're probably a bit unsure what you should be doing. In this blog post, I hope to inspire you to get in there and just dive into programming and to give you a few tips to get started. Read on! *This is not going to be programming language specific and nor should it be - instead I hope to talk in a more general sense about how to go about developing a programmer lifestyle.* ## Step 0: Motivation and Goals The first and most important thing to think about when you want to start programming is ***why*** you want to do it. If you are trying to learn how to program purely because then someone else wants you to or if you want a job as a programmer then just be cautious as you will suffer dearly if you try to force yourself into the mindset of a programmer without any real motivation. The best motives are things such as: - Wanting to build something like an app or website (more on this later) - For the pursuit of knowledge and curiosity, to test oneself - To understand how something works. How does a website actually appear on your browser? This list is not complete in the slightest, nor should you feel deterred by having a reason not mentioned. I am probably missing a lot after all. My point is, you should at some point ***want*** to program. You will stay up late for days on end and spend hours looking at the same pieces of code only to figure out what's wrong and you will hate it. But, it all becomes worth it in the end and the feeling of fulfilment is what keeps you going. There's always some way of solving something, you just need to keep at it. If thinking hard and googling a lot of technical questions and deciphering technical answers doesn't sound fun to you then you're right - its not. What is fun however, is realising that you're learning and that you have benefited from your struggles. Trust me, it is a rewarding hobby (job, whatever). Finding out why you are wanting to program is the key to unlocking the next step, so please think hard and reflect on your own motives before trying to further yourself. ## Step 1: Getting Started Now that you have confirmed that this feels right to you, the next step is to think of a stepping stone towards your goal that is both achievable and interesting to you. I am trying to make this article about recreational programming in the sense that I want to inspire people to program not just for uni or work, but for themselves. This step is hard to talk about, so lets break it down a bit: ### 1.1: Beginners: Learning to code We all have to start somewhere, and for the people who have little to no programming skills then this is the place! The fact you are reading this very sentence proves you are nerdy enough to have business with the computing world. After you have read this section make sure you read the other sections too, particularly step 2 onwards which provides advice for everyone. Below are a few suggestions on how to get started programming. Think about your goal, do a bit of googling and find what languages you should be learning. **DO NOT try and embark on a big project, whatever you do. The most important thing for you right now is getting knowledge, not projects, under your belt.** - [Code Academy](https://www.codecademy.com/) for learning the basics of many languages. I highly recommend you at least have a go at a language that you've found to be necessary to meet your goals. - [CS50](https://cs50.harvard.edu/) Harvard University allows you to actually audit their computer science course! They allow you to do assignments and watch lectures through [EDX](https://www.edx.org/course/introduction-computer-science-harvardx-cs50x), which is pretty amazing. Be aware that while they may still be working with C it will still be beneficial to you. A lot of knowledge is transferable across languages! - Learn through doing. Sure, take out a book from your local library or watch YouTube videos but make sure your fingers are on your keyboard. Trust me, the people who don't type and just sit there during university assignments never learn as much. That's why the above 2 links are great as they are interactive. - Google it! Do not be afraid to look up how to do something. After self teaching so much (including how to set up this blog) I can testify that the internet is indeed your friend. Most of the things you learn will be copied from other individuals. - [Code Avengers](https://www.codeavengers.com/) is something I have heard but have never tried. I'm just listing it here for completeness. Note: If you are wanting to learn web development then you need to be more specific. Do you want to learn networking and how to set up the websites in depth, or do you want to be a front end developer (the part of the website people see). If you are interested in the latter then your mind has to be as creative as it is logical and there will be a ***lot*** of competition. Best of luck! Remember to read the rest of the article to get a feeling of the world of programming. You never know, you might be ready for the next step already! ### 1.2: Knowledgeable: Applying Knowledge This section is for the people who have already learned how to program in some way who either do / have done it as part of an academic course or for work, but do not know how to transfer their skills into something they *want* to do. I like to think this is what sets me apart from some people at my university as I really enjoy working on things in my spare time and I love learning. Sure, we all learn how to program as part of our course, but I'd be lying to say that when we were asked to make a game we didn't stand out. We did pretty well! (work in progress shown below)  The key to becoming a better programmer is to actually do something instead of browsing /g/. Same as before, here are a few things you should try out. I'm not going to talk about learning programming, I'm instead going to talk about applying it in different ways. - Contribute to other people's projects. If you are not familiar with [GitHub](http://github.com) then please read the section coming up. It is *vital* for any programmer to use source control and GitHub is one of the best. - Make something. Take a language you know (or you don't know - plot twist!) and try and make something neat. It could be beneficial to mankind or just a proof of concept. - Get inspired by others. A lot of programmers blog or have some space on the internet where they show off their achievements. I'm not saying you should feel bad for not achieving much if that's the case, I'm just saying that looking at the success of others can make you feel more productive and give you the nudge you need to become productive. - Communicate with other programmers of different skill. Talk to people who are weaker and inspire them and similarly talk to people who are better than you and feel inspired from them. Try [Gitter](https://gitter.im/), a place where programmers can chat and collaborate. For instance, I wanted to learn [MonoGame](http://www.monogame.net/) and so I took to Gitter to ask for advice and if I ever got stuck I had people who enjoyed solving issues. - Try Linux. Sounds really stupid I know, but you don't know how many new programmers just use Windows and Visual Studio. Get Linux and start simple with [Ubuntu](https://www.ubuntu.com/) or something. Then, learn Vim or Emacs (I prefer Emacs with Evil Mode - the best of both worlds!). You will learn how to program more efficiently and love using your keyboard over your mouse. Additionally, you will learn how to compile programs without an IDE, how to work a computer with just a terminal (perfect for servers!) and finally why so many people love Linux for programming. ## Step 2: Embarking on a project Now you need to consider what you're going to make for the time being. This is going to be different to your end goal and is going to be something specific to you. You need to really consider what you are going to get out of the project and whether or not you can actually accomplish it. Don't pick something too easy or too hard - ideally you are going to learn new things by applying things you already know. Making a game in whatever language you know is a great method of just messing around. Test yourself a bit! Anyone can play a game and so you should be able to show people and they can test and feedback to you. If a game isn't appropriate then pick something which you can imagine the end goal of. If you can picture how the program or website is supposed to look or perform and you have a feeling then you should start thinking about how you should go about programming it. If you've taken any sort of class on programming you will have heard a the phrase "*divide and conquer*". This is essentially the notion of splitting up a large task into smaller, manageable chunks and taking it step by step. On the surface this is just some sort of life lesson. It is only when you think of it in terms of programming that it makes more sense; take any activity your program should be able to fulfil and think about the necessary steps required to make it happen. If you want some style points you should consider the system as a whole and try to group common functionality into classes and functions. If you don't know what I'm on about you should look up ***Object Oriented Programming***. If you really want to get serious or if you are working with other people, consider drawing a diagram of some sort or listing the different parts of your program that need implementing. You can then delegate these tasks to your team or simply visualise your progress as you go. Things like this are also great to post on the readme of your GitHub repository (more on that later) so that people who don't want to trawl through your code have some sort of visual indicator of how the program is coming along. If what your making is a website then make sure to include a link to your website somewhere on the actual readme so that people can look at it. ## Step 3: Staying on Goal To some, programming is hard. To others, it is cruel. While it may be both of these things it can also be neither. It is important to remind yourself why you're programming and to constantly evaluate your progress and interest. If you become bored or dissatisfied then simply look at another field - the beauty of programming is that its a frame of mind; once you have it you can learn something new at an accelerated rate. This section is about how you can stay focused on what you set out to do. What's the point in starting something if you don't reach a point of success somewhere down the line? Having a set of tools that make programming enjoyable and easier are vital for survival. If you need some insight in terms of the programming itself, feel free to check out my other blog posts. Currently, my post [Mistakes, and why you need them](https://blog.aas.sh/Mistakes) is the only other post which talks briefly about what you go through while programming. If in doubt, look what your compiler or your built program is feeding back to you, isolate the code that is making it function that way and fix it. Don't **EVER** let a problem halt a project. If there's any reason to abandon something *don't ever let it be some sort of bug or compiler error*. In face, these are the things you should be craving as you will develop your skills as a programmer, debugger and a researcher all at once. ### 3.1: [Github](http://GitHub.com) I've talked about this previously and I'm going to talk about it again. Any programming enthusiast needs source control and a space on the internet where they can see what they've done. #### What is GitHub anyway? "*GitHub is a development platform inspired by the way you work. From open source to business, you can host and review code, manage projects, and build software alongside millions of other developers.*" In English, GitHub is a space where you can upload coding projects and collaborate with other people easily. Even when working solo having a code repository is crucial. If you make a mistake or if your computer fails then there will always be the last "commit" online. A commit is essentially a snapshot of your program. The reason GitHub is better than something like Dropbox is because of the fact that it is intelligent to notice changes in your code. It only uploads and downloads the new code (a massive time-save with large projects) and summarises the commit with a helpful message along with the lines that have been added and deleted. I'm not going to go too much into this, [so please read this and get started NOW.](https://guides.github.com/activities/hello-world/). Another thing to note is that if you work in multiple places, with multiple people or on multiple machines, being able to download what's new and upload your progress (while automatically merging your work with any made by collaborators) is an amazing routine to get in. It keeps everyone and everything on the same page while also keep a log of every change to the project. #### Why would I want people looking at my code? Firstly, you can make private repositories if you really want to. It requires a subscription to the paid GitHub service, [but students can get this for free](https://education.github.com/pack). I would suggest however, that any project containing non-sensitive info should be public. Why? Well, firstly other people may want to help you out by suggesting fixes, more secure / semantic functions or by simply reporting bugs. Secondly, it will show that you're an active programmer. Anyone (including potential employers) could look at your public repo and see exactly how much progress you've made. If seeing you work on your own projects isn't enough, then ***simply using GitHub can sometimes be a deal-breaker***. Source control is very important to serious developers, the last thing they want is to hire someone with no knowledge of committing to a repo. Don't be worried about people stealing your code. It is much more of a benefit to you to be open and honest about what you have created than it is to be paranoid and making everything you do private. If you're a business or you're planning on monetizing something then make it private, go ahead. But as a small, hobbyist programmer be a little more real and realise that 90% of the people on GitHub could probably make something better anyway - they won't care about stealing your code. Instead, they will help your code become better! If stealing code was a problem then people wouldn't go public with the majority of their repos. #### Why GitHub and not another source control service? Please shut up and just use GitHub. While there are many valid services out there, GitHub is extremely popular and most programmers use it. If you're only looking for source control then maybe looking for a service that offers free private repos would be in your interest, however do not underestimate the importance of others reviewing your code. ### 3.2: Upgrade your setup I cannot stress this enough. Learning the Vi keyboard shortcuts has been a mini-challenge and has helped me enjoy programming even more. Sure, it slowed me down in the beginning but now I am comfortable with navigating any piece of software that supports Vi shortcuts (or Vi emulation plugins) without a mouse. Adobe Brackets, Visual Studio, Google Chrome, GitHub, Googlemail all use / can use Vi shortcuts and it is **FUN**.  [Playing this simple game, Vim Adventures](https://vim-adventures.com/) really helped me get started. The gif I made doesn't really do it justice, but seriously try it out. I didn't understand why it was so popular until I started coding with it and wow am I having fun. Notice I am talking about fun here - it may take a while for me to be productive enough to make this effort worth it, but the fact that I enjoy merely typing is a big boost to my productivity. Why do I keep going on about a text editor? Simple: I enjoy adapting my editor to look and feel cool and unique to me. As I type this it may not be the most amazing [emacs.d](https://github.com/Crysikrend/emacs) it is my own and I'm slowly learning how to make appeal to me. People use emacs as a web browser, as a [note taker](http://orgmode.org/) and as a text editor that can be extended for ***any language***. Trust me, its really neat and if you use Linux or a Mac I'd honestly give it a shot. I will probably make a blog post on how to get started with it, but a bit of googling should help. Note that there are some amazing plugins that allow you to use GitHub within emacs, reinforcing that GitHub is important! If you're on Windows then to be honest you are stuck with Visual Studio for most of your coding needs. I have to admit, you cannot really do much better. If you really wanted to, try using a virtual machine and run a Linux distro so you can see what I'm talking about. You can also look at editors like [Adobe Brackets](http://brackets.io/), [Atom](https://atom.io/) and [Sublime text](https://www.sublimetext.com/) if you're working with code that you don't need an IDE for (Web Development) and you're on Windows. Just in case you didn't know, an IDE is a piece of software that can compile and debug your programs easily in. [Visual Studio](https://www.visualstudio.com/) is probably the best thing on Windows, but there are other IDEs like [Rider by JetBrains](https://www.jetbrains.com/rider/) if you're working with C#. Note that JetBrains have lots of cool IDEs to look at if you want a change to Visual Studio or if you're on a different operating system. If you're doing games development like I am, try a new engine (or if you haven't tried it, try making your own!). When I first opened up [Unreal](https://www.unrealengine.com/) in January I was a little confused, but I slowly learned. After making a game with it I now understand why I enjoy the challenge making a game in pure code. Just a preference, but having more engines under your belt doesn't hurt! ## Step 4: Network Another thing I wanted to mention is how important it is to stay social about your hobby/goals. Tell people what progress you're making and what you want to do next. If they're a programmer also then you can also show them your GitHub repo and talk about how you implemented certain features. Speaking personally, people wanted to know how we made our level 'explode' (shown in the gif in this post). I previously mentioned [Gitter](https://gitter.im/) to be pretty good at getting in touch with people. If you haven't guessed already, it has integration with GitHub! Anyone you speak to on here not only has their own stories, motives and goals but also the repositories to go with them. Find a Gitter room that is related to your project and just chill. There's obviously more than Gitter out there. There's the usual [Reddit](http://reddit.com) for sub-communities, [/g/](http://boards.4chan.org/g/) for discussions and even [Discord servers](discordapp.com) for when you find a community that has one. I am personally in a [Gamesdev Discord](https://discordapp.com/invite/gamedev) and a [Webdev Discord](https://discordapp.com/invite/wdg) and have used both thoroughly. It is important to talk to people - even if you don't know them. You will learn how people who are stronger programmers than you are operate and how they would go about something you're trying to do. I have made a **HUGE** point about GitHub in this article as frankly I'm appalled at how many people on my course do not utilize such a useful tool. Most of the people you talk to will have GitHub profiles so hopefully if I haven't convinced you then the rest of the programming world will. *Seriously, just try it if you haven't already.* ## Step 5: Finishing and Maintaining Not many people choose to do these things, however if you do have a repo on GitHub you should try and make sure you keep a version that is *working as intended* committed. If you want to go in-depth, create a development branch so that any commits you make do not affect the master branch. Then, when you have a new, stable build, commit to the master branch and everyone's happy. The reason I am talking about the end of a project is because it is awfully tempting to abandon a project once you have learned what you can from it. Personally, I have stopped work on [Sprinty](http://github.com/crysikrend/sprinty) ever since Uni started again. It works, sure, but I wish I actually continued it, added new things and ported it to Android like I intended. I am probably never going to actually finish this, but it would be awfully impressive if I did. If I wanted to work with Monogame more, I would, but right now my attention is on [SDL](https://www.libsdl.org/), which is essentially Monogame but C++. If you do manage to finish a project then you should do everything in your power to maintain it. Let's say you made a plugin for some software, or an extension to make a website better - if that website or software changes in some way then your program breaks down. Maybe no one will care, but if someone was to check out your portfolio and find something broken without you giving a good reason on the readme then it may make you out as someone who doesn't test their code thoroughly. ## Wrapping things up I hope this post has been somewhat helpful. I think more people who have programming jobs or who program as part of a university course should try and embrace programming as a hobby as well as a job. I may not be a professional (right now) but apparently I'm pretty good at picking up new things and teaching people what I know, so hopefully now you know just as much as I do about how to get started with doing. If you are really, **really** new to programming and you found this article dissatisfying, let me know. I chose to focus on the people who have some knowledge as its very common for people to create tutorials about the extreme basics of programming - its easy and everyone who programs understands it. The hard thing to talk about is the grey blur between learning about what a function is and how to make a game purely out of code using DirectX, for instance. There are many places out there that will teach you how to code, and I hope that once you have any sort of grasp on it you will think about the things I have talked about and get started with making something for yourself! I have finished Uni for the year and so now have much more free time. My studio, [BestInSlot](http://BestInSlot.gg), got accepted for a placement scheme and so next year we can hopefully develop and market our very own game. Exciting! Keep an eye on my [Twitter](http://twitter.com/crysikrend) for updates and feel free to comment if you need advice on anything I've talked about. Similarly, comment down below if you have found this article helpful as I put quite a lot of time in! Until next time! |
| json metadata | {"tags":["programming","beginners","guide","how","start"],"image":["/content/2017-02/alacrity.gif","/content/2017-04/vimadventures.gif"],"links":["https://blog.aas.sh/posts/2017-04-11-Start-Programming/","https://www.codecademy.com/","https://cs50.harvard.edu/","https://www.edx.org/course/introduction-computer-science-harvardx-cs50x","https://www.codeavengers.com/","http://github.com","https://gitter.im/","http://www.monogame.net/","https://www.ubuntu.com/","https://blog.aas.sh/Mistakes","http://GitHub.com","https://guides.github.com/activities/hello-world/","https://education.github.com/pack","https://vim-adventures.com/","https://github.com/Crysikrend/emacs","http://orgmode.org/","http://brackets.io/","https://atom.io/","https://www.sublimetext.com/","https://www.visualstudio.com/","https://www.jetbrains.com/rider/","https://www.unrealengine.com/","http://reddit.com","http://boards.4chan.org/g/","discordapp.com","https://discordapp.com/invite/gamedev","https://discordapp.com/invite/wdg","http://github.com/crysikrend/sprinty","https://www.libsdl.org/","http://BestInSlot.gg","http://twitter.com/crysikrend"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25411851/Trx a17ebf35c90467005495fde642510f5a74144fb0 |
View Raw JSON Data
{
"trx_id": "a17ebf35c90467005495fde642510f5a74144fb0",
"block": 25411851,
"trx_in_block": 23,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:33:48",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "programming",
"author": "aas-sh",
"permlink": "get-started-with-programming",
"title": "Get started with programming!",
"body": "> This post can be found on my blog [here.](https://blog.aas.sh/posts/2017-04-11-Start-Programming/)\n\nIt took me a while to figure my way around Steemit so I apologise for the deleted blogs!\n\nSo you've been using the internet competently for many years of your life and you've become interested in programming - great! However, you're probably a bit unsure what you should be doing. In this blog post, I hope to inspire you to get in there and just dive into programming and to give you a few tips to get started. Read on!\n\n*This is not going to be programming language specific and nor should it be - instead I hope to talk in a more general sense about how to go about developing a programmer lifestyle.*\n\n## Step 0: Motivation and Goals\nThe first and most important thing to think about when you want to start programming is ***why*** you want to do it. If you are trying to learn how to program purely because then someone else wants you to or if you want a job as a programmer then just be cautious as you will suffer dearly if you try to force yourself into the mindset of a programmer without any real motivation.\n\nThe best motives are things such as:\n- Wanting to build something like an app or website (more on this later)\n- For the pursuit of knowledge and curiosity, to test oneself\n- To understand how something works. How does a website actually appear on your browser?\n\nThis list is not complete in the slightest, nor should you feel deterred by having a reason not mentioned. I am probably missing a lot after all. My point is, you should at some point ***want*** to program. You will stay up late for days on end and spend hours looking at the same pieces of code only to figure out what's wrong and you will hate it. But, it all becomes worth it in the end and the feeling of fulfilment is what keeps you going. There's always some way of solving something, you just need to keep at it. If thinking hard and googling a lot of technical questions and deciphering technical answers doesn't sound fun to you then you're right - its not. What is fun however, is realising that you're learning and that you have benefited from your struggles. Trust me, it is a rewarding hobby (job, whatever).\n\nFinding out why you are wanting to program is the key to unlocking the next step, so please think hard and reflect on your own motives before trying to further yourself.\n\n## Step 1: Getting Started\nNow that you have confirmed that this feels right to you, the next step is to think of a stepping stone towards your goal that is both achievable and interesting to you. I am trying to make this article about recreational programming in the sense that I want to inspire people to program not just for uni or work, but for themselves.\n\nThis step is hard to talk about, so lets break it down a bit:\n\n### 1.1: Beginners: Learning to code\nWe all have to start somewhere, and for the people who have little to no programming skills then this is the place! The fact you are reading this very sentence proves you are nerdy enough to have business with the computing world. After you have read this section make sure you read the other sections too, particularly step 2 onwards which provides advice for everyone.\n\nBelow are a few suggestions on how to get started programming. Think about your goal, do a bit of googling and find what languages you should be learning. **DO NOT try and embark on a big project, whatever you do. The most important thing for you right now is getting knowledge, not projects, under your belt.**\n\n- [Code Academy](https://www.codecademy.com/) for learning the basics of many languages. I highly recommend you at least have a go at a language that you've found to be necessary to meet your goals.\n- [CS50](https://cs50.harvard.edu/) Harvard University allows you to actually audit their computer science course! They allow you to do assignments and watch lectures through [EDX](https://www.edx.org/course/introduction-computer-science-harvardx-cs50x), which is pretty amazing. Be aware that while they may still be working with C it will still be beneficial to you. A lot of knowledge is transferable across languages!\n- Learn through doing. Sure, take out a book from your local library or watch YouTube videos but make sure your fingers are on your keyboard. Trust me, the people who don't type and just sit there during university assignments never learn as much. That's why the above 2 links are great as they are interactive.\n- Google it! Do not be afraid to look up how to do something. After self teaching so much (including how to set up this blog) I can testify that the internet is indeed your friend. Most of the things you learn will be copied from other individuals.\n- [Code Avengers](https://www.codeavengers.com/) is something I have heard but have never tried. I'm just listing it here for completeness.\n\nNote: If you are wanting to learn web development then you need to be more specific. Do you want to learn networking and how to set up the websites in depth, or do you want to be a front end developer (the part of the website people see). If you are interested in the latter then your mind has to be as creative as it is logical and there will be a ***lot*** of competition. Best of luck!\n\nRemember to read the rest of the article to get a feeling of the world of programming. You never know, you might be ready for the next step already!\n\n### 1.2: Knowledgeable: Applying Knowledge\nThis section is for the people who have already learned how to program in some way who either do / have done it as part of an academic course or for work, but do not know how to transfer their skills into something they *want* to do. I like to think this is what sets me apart from some people at my university as I really enjoy working on things in my spare time and I love learning. Sure, we all learn how to program as part of our course, but I'd be lying to say that when we were asked to make a game we didn't stand out. We did pretty well! (work in progress shown below)\n\n\n\nThe key to becoming a better programmer is to actually do something instead of browsing /g/. Same as before, here are a few things you should try out. I'm not going to talk about learning programming, I'm instead going to talk about applying it in different ways.\n\n- Contribute to other people's projects. If you are not familiar with [GitHub](http://github.com) then please read the section coming up. It is *vital* for any programmer to use source control and GitHub is one of the best.\n- Make something. Take a language you know (or you don't know - plot twist!) and try and make something neat. It could be beneficial to mankind or just a proof of concept.\n- Get inspired by others. A lot of programmers blog or have some space on the internet where they show off their achievements. I'm not saying you should feel bad for not achieving much if that's the case, I'm just saying that looking at the success of others can make you feel more productive and give you the nudge you need to become productive.\n- Communicate with other programmers of different skill. Talk to people who are weaker and inspire them and similarly talk to people who are better than you and feel inspired from them. Try [Gitter](https://gitter.im/), a place where programmers can chat and collaborate. For instance, I wanted to learn [MonoGame](http://www.monogame.net/) and so I took to Gitter to ask for advice and if I ever got stuck I had people who enjoyed solving issues.\n- Try Linux. Sounds really stupid I know, but you don't know how many new programmers just use Windows and Visual Studio. Get Linux and start simple with [Ubuntu](https://www.ubuntu.com/) or something. Then, learn Vim or Emacs (I prefer Emacs with Evil Mode - the best of both worlds!). You will learn how to program more efficiently and love using your keyboard over your mouse. Additionally, you will learn how to compile programs without an IDE, how to work a computer with just a terminal (perfect for servers!) and finally why so many people love Linux for programming.\n\n## Step 2: Embarking on a project\nNow you need to consider what you're going to make for the time being. This is going to be different to your end goal and is going to be something specific to you. You need to really consider what you are going to get out of the project and whether or not you can actually accomplish it. Don't pick something too easy or too hard - ideally you are going to learn new things by applying things you already know.\n\nMaking a game in whatever language you know is a great method of just messing around. Test yourself a bit! Anyone can play a game and so you should be able to show people and they can test and feedback to you. If a game isn't appropriate then pick something which you can imagine the end goal of. If you can picture how the program or website is supposed to look or perform and you have a feeling then you should start thinking about how you should go about programming it.\n\nIf you've taken any sort of class on programming you will have heard a the phrase \"*divide and conquer*\". This is essentially the notion of splitting up a large task into smaller, manageable chunks and taking it step by step. On the surface this is just some sort of life lesson. It is only when you think of it in terms of programming that it makes more sense; take any activity your program should be able to fulfil and think about the necessary steps required to make it happen. If you want some style points you should consider the system as a whole and try to group common functionality into classes and functions. If you don't know what I'm on about you should look up ***Object Oriented Programming***.\n\nIf you really want to get serious or if you are working with other people, consider drawing a diagram of some sort or listing the different parts of your program that need implementing. You can then delegate these tasks to your team or simply visualise your progress as you go. Things like this are also great to post on the readme of your GitHub repository (more on that later) so that people who don't want to trawl through your code have some sort of visual indicator of how the program is coming along. If what your making is a website then make sure to include a link to your website somewhere on the actual readme so that people can look at it.\n\n## Step 3: Staying on Goal\nTo some, programming is hard. To others, it is cruel. While it may be both of these things it can also be neither. It is important to remind yourself why you're programming and to constantly evaluate your progress and interest. If you become bored or dissatisfied then simply look at another field - the beauty of programming is that its a frame of mind; once you have it you can learn something new at an accelerated rate.\n\nThis section is about how you can stay focused on what you set out to do. What's the point in starting something if you don't reach a point of success somewhere down the line? Having a set of tools that make programming enjoyable and easier are vital for survival.\n\nIf you need some insight in terms of the programming itself, feel free to check out my other blog posts. Currently, my post [Mistakes, and why you need them](https://blog.aas.sh/Mistakes) is the only other post which talks briefly about what you go through while programming. If in doubt, look what your compiler or your built program is feeding back to you, isolate the code that is making it function that way and fix it. Don't **EVER** let a problem halt a project. If there's any reason to abandon something *don't ever let it be some sort of bug or compiler error*. In face, these are the things you should be craving as you will develop your skills as a programmer, debugger and a researcher all at once.\n\n### 3.1: [Github](http://GitHub.com)\nI've talked about this previously and I'm going to talk about it again. Any programming enthusiast needs source control and a space on the internet where they can see what they've done.\n\n#### What is GitHub anyway?\n\"*GitHub is a development platform inspired by the way you work. From open source to business, you can host and review code, manage projects, and build software alongside millions of other developers.*\" In English, GitHub is a space where you can upload coding projects and collaborate with other people easily. Even when working solo having a code repository is crucial. If you make a mistake or if your computer fails then there will always be the last \"commit\" online.\n\nA commit is essentially a snapshot of your program. The reason GitHub is better than something like Dropbox is because of the fact that it is intelligent to notice changes in your code. It only uploads and downloads the new code (a massive time-save with large projects) and summarises the commit with a helpful message along with the lines that have been added and deleted. I'm not going to go too much into this, [so please read this and get started NOW.](https://guides.github.com/activities/hello-world/).\n\nAnother thing to note is that if you work in multiple places, with multiple people or on multiple machines, being able to download what's new and upload your progress (while automatically merging your work with any made by collaborators) is an amazing routine to get in. It keeps everyone and everything on the same page while also keep a log of every change to the project.\n\n#### Why would I want people looking at my code?\nFirstly, you can make private repositories if you really want to. It requires a subscription to the paid GitHub service, [but students can get this for free](https://education.github.com/pack). I would suggest however, that any project containing non-sensitive info should be public. Why? Well, firstly other people may want to help you out by suggesting fixes, more secure / semantic functions or by simply reporting bugs. Secondly, it will show that you're an active programmer. Anyone (including potential employers) could look at your public repo and see exactly how much progress you've made.\n\nIf seeing you work on your own projects isn't enough, then ***simply using GitHub can sometimes be a deal-breaker***. Source control is very important to serious developers, the last thing they want is to hire someone with no knowledge of committing to a repo.\n\nDon't be worried about people stealing your code. It is much more of a benefit to you to be open and honest about what you have created than it is to be paranoid and making everything you do private. If you're a business or you're planning on monetizing something then make it private, go ahead. But as a small, hobbyist programmer be a little more real and realise that 90% of the people on GitHub could probably make something better anyway - they won't care about stealing your code. Instead, they will help your code become better! If stealing code was a problem then people wouldn't go public with the majority of their repos.\n\n#### Why GitHub and not another source control service?\nPlease shut up and just use GitHub. While there are many valid services out there, GitHub is extremely popular and most programmers use it. If you're only looking for source control then maybe looking for a service that offers free private repos would be in your interest, however do not underestimate the importance of others reviewing your code.\n\n### 3.2: Upgrade your setup\nI cannot stress this enough. Learning the Vi keyboard shortcuts has been a mini-challenge and has helped me enjoy programming even more. Sure, it slowed me down in the beginning but now I am comfortable with navigating any piece of software that supports Vi shortcuts (or Vi emulation plugins) without a mouse. Adobe Brackets, Visual Studio, Google Chrome, GitHub, Googlemail all use / can use Vi shortcuts and it is **FUN**.\n\n\n\n[Playing this simple game, Vim Adventures](https://vim-adventures.com/) really helped me get started. The gif I made doesn't really do it justice, but seriously try it out. I didn't understand why it was so popular until I started coding with it and wow am I having fun. Notice I am talking about fun here - it may take a while for me to be productive enough to make this effort worth it, but the fact that I enjoy merely typing is a big boost to my productivity.\n\nWhy do I keep going on about a text editor? Simple: I enjoy adapting my editor to look and feel cool and unique to me. As I type this it may not be the most amazing [emacs.d](https://github.com/Crysikrend/emacs) it is my own and I'm slowly learning how to make appeal to me. People use emacs as a web browser, as a [note taker](http://orgmode.org/) and as a text editor that can be extended for ***any language***. Trust me, its really neat and if you use Linux or a Mac I'd honestly give it a shot. I will probably make a blog post on how to get started with it, but a bit of googling should help. Note that there are some amazing plugins that allow you to use GitHub within emacs, reinforcing that GitHub is important!\n\nIf you're on Windows then to be honest you are stuck with Visual Studio for most of your coding needs. I have to admit, you cannot really do much better. If you really wanted to, try using a virtual machine and run a Linux distro so you can see what I'm talking about. You can also look at editors like [Adobe Brackets](http://brackets.io/), [Atom](https://atom.io/) and [Sublime text](https://www.sublimetext.com/) if you're working with code that you don't need an IDE for (Web Development) and you're on Windows.\n\nJust in case you didn't know, an IDE is a piece of software that can compile and debug your programs easily in. [Visual Studio](https://www.visualstudio.com/) is probably the best thing on Windows, but there are other IDEs like [Rider by JetBrains](https://www.jetbrains.com/rider/) if you're working with C#. Note that JetBrains have lots of cool IDEs to look at if you want a change to Visual Studio or if you're on a different operating system.\n\nIf you're doing games development like I am, try a new engine (or if you haven't tried it, try making your own!). When I first opened up [Unreal](https://www.unrealengine.com/) in January I was a little confused, but I slowly learned. After making a game with it I now understand why I enjoy the challenge making a game in pure code. Just a preference, but having more engines under your belt doesn't hurt!\n\n## Step 4: Network\nAnother thing I wanted to mention is how important it is to stay social about your hobby/goals. Tell people what progress you're making and what you want to do next. If they're a programmer also then you can also show them your GitHub repo and talk about how you implemented certain features. Speaking personally, people wanted to know how we made our level 'explode' (shown in the gif in this post).\n\nI previously mentioned [Gitter](https://gitter.im/) to be pretty good at getting in touch with people. If you haven't guessed already, it has integration with GitHub! Anyone you speak to on here not only has their own stories, motives and goals but also the repositories to go with them. Find a Gitter room that is related to your project and just chill.\n\nThere's obviously more than Gitter out there. There's the usual [Reddit](http://reddit.com) for sub-communities, [/g/](http://boards.4chan.org/g/) for discussions and even [Discord servers](discordapp.com) for when you find a community that has one. I am personally in a [Gamesdev Discord](https://discordapp.com/invite/gamedev) and a [Webdev Discord](https://discordapp.com/invite/wdg) and have used both thoroughly.\n\nIt is important to talk to people - even if you don't know them. You will learn how people who are stronger programmers than you are operate and how they would go about something you're trying to do. I have made a **HUGE** point about GitHub in this article as frankly I'm appalled at how many people on my course do not utilize such a useful tool. Most of the people you talk to will have GitHub profiles so hopefully if I haven't convinced you then the rest of the programming world will. *Seriously, just try it if you haven't already.*\n\n## Step 5: Finishing and Maintaining\nNot many people choose to do these things, however if you do have a repo on GitHub you should try and make sure you keep a version that is *working as intended* committed. If you want to go in-depth, create a development branch so that any commits you make do not affect the master branch. Then, when you have a new, stable build, commit to the master branch and everyone's happy.\n\nThe reason I am talking about the end of a project is because it is awfully tempting to abandon a project once you have learned what you can from it. Personally, I have stopped work on [Sprinty](http://github.com/crysikrend/sprinty) ever since Uni started again. It works, sure, but I wish I actually continued it, added new things and ported it to Android like I intended. I am probably never going to actually finish this, but it would be awfully impressive if I did. If I wanted to work with Monogame more, I would, but right now my attention is on [SDL](https://www.libsdl.org/), which is essentially Monogame but C++.\n\nIf you do manage to finish a project then you should do everything in your power to maintain it. Let's say you made a plugin for some software, or an extension to make a website better - if that website or software changes in some way then your program breaks down. Maybe no one will care, but if someone was to check out your portfolio and find something broken without you giving a good reason on the readme then it may make you out as someone who doesn't test their code thoroughly.\n\n## Wrapping things up\nI hope this post has been somewhat helpful. I think more people who have programming jobs or who program as part of a university course should try and embrace programming as a hobby as well as a job. I may not be a professional (right now) but apparently I'm pretty good at picking up new things and teaching people what I know, so hopefully now you know just as much as I do about how to get started with doing.\n\nIf you are really, **really** new to programming and you found this article dissatisfying, let me know. I chose to focus on the people who have some knowledge as its very common for people to create tutorials about the extreme basics of programming - its easy and everyone who programs understands it. The hard thing to talk about is the grey blur between learning about what a function is and how to make a game purely out of code using DirectX, for instance. There are many places out there that will teach you how to code, and I hope that once you have any sort of grasp on it you will think about the things I have talked about and get started with making something for yourself!\n\nI have finished Uni for the year and so now have much more free time. My studio, [BestInSlot](http://BestInSlot.gg), got accepted for a placement scheme and so next year we can hopefully develop and market our very own game. Exciting!\n\nKeep an eye on my [Twitter](http://twitter.com/crysikrend) for updates and feel free to comment if you need advice on anything I've talked about. Similarly, comment down below if you have found this article helpful as I put quite a lot of time in!\n\nUntil next time!",
"json_metadata": "{\"tags\":[\"programming\",\"beginners\",\"guide\",\"how\",\"start\"],\"image\":[\"/content/2017-02/alacrity.gif\",\"/content/2017-04/vimadventures.gif\"],\"links\":[\"https://blog.aas.sh/posts/2017-04-11-Start-Programming/\",\"https://www.codecademy.com/\",\"https://cs50.harvard.edu/\",\"https://www.edx.org/course/introduction-computer-science-harvardx-cs50x\",\"https://www.codeavengers.com/\",\"http://github.com\",\"https://gitter.im/\",\"http://www.monogame.net/\",\"https://www.ubuntu.com/\",\"https://blog.aas.sh/Mistakes\",\"http://GitHub.com\",\"https://guides.github.com/activities/hello-world/\",\"https://education.github.com/pack\",\"https://vim-adventures.com/\",\"https://github.com/Crysikrend/emacs\",\"http://orgmode.org/\",\"http://brackets.io/\",\"https://atom.io/\",\"https://www.sublimetext.com/\",\"https://www.visualstudio.com/\",\"https://www.jetbrains.com/rider/\",\"https://www.unrealengine.com/\",\"http://reddit.com\",\"http://boards.4chan.org/g/\",\"discordapp.com\",\"https://discordapp.com/invite/gamedev\",\"https://discordapp.com/invite/wdg\",\"http://github.com/crysikrend/sprinty\",\"https://www.libsdl.org/\",\"http://BestInSlot.gg\",\"http://twitter.com/crysikrend\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}aas-shdeleted a comment or post2018/08/26 17:31:03
aas-shdeleted a comment or post
2018/08/26 17:31:03
| author | aas-sh |
| permlink | 6mpge2-start-programming |
| Transaction Info | Block #25411796/Trx 1ac36720788a4211af8241b382b77d74efdd653b |
View Raw JSON Data
{
"trx_id": "1ac36720788a4211af8241b382b77d74efdd653b",
"block": 25411796,
"trx_in_block": 25,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:31:03",
"op": [
"delete_comment",
{
"author": "aas-sh",
"permlink": "6mpge2-start-programming"
}
]
}aas-shflagged (-100.00%) @aas-sh / 6mpge2-start-programming2018/08/26 17:30:57
aas-shflagged (-100.00%) @aas-sh / 6mpge2-start-programming
2018/08/26 17:30:57
| voter | aas-sh |
| author | aas-sh |
| permlink | 6mpge2-start-programming |
| weight | -10000 (-100.00%) |
| Transaction Info | Block #25411794/Trx d174e4ca72a0ef729e9afb736c05329ef50b93b3 |
View Raw JSON Data
{
"trx_id": "d174e4ca72a0ef729e9afb736c05329ef50b93b3",
"block": 25411794,
"trx_in_block": 22,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:30:57",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "aas-sh",
"permlink": "6mpge2-start-programming",
"weight": -10000
}
]
}aas-shpublished a new post: 6mpge2-start-programming2018/08/26 17:30:51
aas-shpublished a new post: 6mpge2-start-programming
2018/08/26 17:30:51
| parent author | |
| parent permlink | programming |
| author | aas-sh |
| permlink | 6mpge2-start-programming |
| title | del |
| body | del |
| json metadata | {"tags":["programming"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25411792/Trx c2378cd61ae63764aa90c25fed0956f5d5448fa4 |
View Raw JSON Data
{
"trx_id": "c2378cd61ae63764aa90c25fed0956f5d5448fa4",
"block": 25411792,
"trx_in_block": 59,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:30:51",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "programming",
"author": "aas-sh",
"permlink": "6mpge2-start-programming",
"title": "del",
"body": "del",
"json_metadata": "{\"tags\":[\"programming\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}ggd3yydzeupvoted (100.00%) @aas-sh / 6mpge2-start-programming2018/08/26 17:29:30
ggd3yydzeupvoted (100.00%) @aas-sh / 6mpge2-start-programming
2018/08/26 17:29:30
| voter | ggd3yydze |
| author | aas-sh |
| permlink | 6mpge2-start-programming |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25411765/Trx cb626aadd8f1a876db5370b789c6a816b7f60683 |
View Raw JSON Data
{
"trx_id": "cb626aadd8f1a876db5370b789c6a816b7f60683",
"block": 25411765,
"trx_in_block": 16,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:29:30",
"op": [
"vote",
{
"voter": "ggd3yydze",
"author": "aas-sh",
"permlink": "6mpge2-start-programming",
"weight": 10000
}
]
}aas-shpublished a new post: 6mpge2-start-programming2018/08/26 17:28:33
aas-shpublished a new post: 6mpge2-start-programming
2018/08/26 17:28:33
| parent author | |
| parent permlink | programming |
| author | aas-sh |
| permlink | 6mpge2-start-programming |
| title | Start Programming |
| body | > This post can be found on my blog [here.](https://blog.aas.sh/posts/2017-04-11-Start-Programming/) So you've been using the internet competently for many years of your life and you've become interested in programming - great! However, you're probably a bit unsure what you should be doing. In this blog post, I hope to inspire you to get in there and just dive into programming and to give you a few tips to get started. Read on! *This is not going to be programming language specific and nor should it be - instead I hope to talk in a more general sense about how to go about developing a programmer lifestyle.* ## Step 0: Motivation and Goals The first and most important thing to think about when you want to start programming is ***why*** you want to do it. If you are trying to learn how to program purely because then someone else wants you to or if you want a job as a programmer then just be cautious as you will suffer dearly if you try to force yourself into the mindset of a programmer without any real motivation. The best motives are things such as: - Wanting to build something like an app or website (more on this later) - For the pursuit of knowledge and curiosity, to test oneself - To understand how something works. How does a website actually appear on your browser? This list is not complete in the slightest, nor should you feel deterred by having a reason not mentioned. I am probably missing a lot after all. My point is, you should at some point ***want*** to program. You will stay up late for days on end and spend hours looking at the same pieces of code only to figure out what's wrong and you will hate it. But, it all becomes worth it in the end and the feeling of fulfilment is what keeps you going. There's always some way of solving something, you just need to keep at it. If thinking hard and googling a lot of technical questions and deciphering technical answers doesn't sound fun to you then you're right - its not. What is fun however, is realising that you're learning and that you have benefited from your struggles. Trust me, it is a rewarding hobby (job, whatever). Finding out why you are wanting to program is the key to unlocking the next step, so please think hard and reflect on your own motives before trying to further yourself. ## Step 1: Getting Started Now that you have confirmed that this feels right to you, the next step is to think of a stepping stone towards your goal that is both achievable and interesting to you. I am trying to make this article about recreational programming in the sense that I want to inspire people to program not just for uni or work, but for themselves. This step is hard to talk about, so lets break it down a bit: ### 1.1: Beginners: Learning to code We all have to start somewhere, and for the people who have little to no programming skills then this is the place! The fact you are reading this very sentence proves you are nerdy enough to have business with the computing world. After you have read this section make sure you read the other sections too, particularly step 2 onwards which provides advice for everyone. Below are a few suggestions on how to get started programming. Think about your goal, do a bit of googling and find what languages you should be learning. **DO NOT try and embark on a big project, whatever you do. The most important thing for you right now is getting knowledge, not projects, under your belt.** - [Code Academy](https://www.codecademy.com/) for learning the basics of many languages. I highly recommend you at least have a go at a language that you've found to be necessary to meet your goals. - [CS50](https://cs50.harvard.edu/) Harvard University allows you to actually audit their computer science course! They allow you to do assignments and watch lectures through [EDX](https://www.edx.org/course/introduction-computer-science-harvardx-cs50x), which is pretty amazing. Be aware that while they may still be working with C it will still be beneficial to you. A lot of knowledge is transferable across languages! - Learn through doing. Sure, take out a book from your local library or watch YouTube videos but make sure your fingers are on your keyboard. Trust me, the people who don't type and just sit there during university assignments never learn as much. That's why the above 2 links are great as they are interactive. - Google it! Do not be afraid to look up how to do something. After self teaching so much (including how to set up this blog) I can testify that the internet is indeed your friend. Most of the things you learn will be copied from other individuals. - [Code Avengers](https://www.codeavengers.com/) is something I have heard but have never tried. I'm just listing it here for completeness. Note: If you are wanting to learn web development then you need to be more specific. Do you want to learn networking and how to set up the websites in depth, or do you want to be a front end developer (the part of the website people see). If you are interested in the latter then your mind has to be as creative as it is logical and there will be a ***lot*** of competition. Best of luck! Remember to read the rest of the article to get a feeling of the world of programming. You never know, you might be ready for the next step already! ### 1.2: Knowledgeable: Applying Knowledge This section is for the people who have already learned how to program in some way who either do / have done it as part of an academic course or for work, but do not know how to transfer their skills into something they *want* to do. I like to think this is what sets me apart from some people at my university as I really enjoy working on things in my spare time and I love learning. Sure, we all learn how to program as part of our course, but I'd be lying to say that when we were asked to make a game we didn't stand out. We did pretty well! (work in progress shown below)  The key to becoming a better programmer is to actually do something instead of browsing /g/. Same as before, here are a few things you should try out. I'm not going to talk about learning programming, I'm instead going to talk about applying it in different ways. - Contribute to other people's projects. If you are not familiar with [GitHub](http://github.com) then please read the section coming up. It is *vital* for any programmer to use source control and GitHub is one of the best. - Make something. Take a language you know (or you don't know - plot twist!) and try and make something neat. It could be beneficial to mankind or just a proof of concept. - Get inspired by others. A lot of programmers blog or have some space on the internet where they show off their achievements. I'm not saying you should feel bad for not achieving much if that's the case, I'm just saying that looking at the success of others can make you feel more productive and give you the nudge you need to become productive. - Communicate with other programmers of different skill. Talk to people who are weaker and inspire them and similarly talk to people who are better than you and feel inspired from them. Try [Gitter](https://gitter.im/), a place where programmers can chat and collaborate. For instance, I wanted to learn [MonoGame](http://www.monogame.net/) and so I took to Gitter to ask for advice and if I ever got stuck I had people who enjoyed solving issues. - Try Linux. Sounds really stupid I know, but you don't know how many new programmers just use Windows and Visual Studio. Get Linux and start simple with [Ubuntu](https://www.ubuntu.com/) or something. Then, learn Vim or Emacs (I prefer Emacs with Evil Mode - the best of both worlds!). You will learn how to program more efficiently and love using your keyboard over your mouse. Additionally, you will learn how to compile programs without an IDE, how to work a computer with just a terminal (perfect for servers!) and finally why so many people love Linux for programming. ## Step 2: Embarking on a project Now you need to consider what you're going to make for the time being. This is going to be different to your end goal and is going to be something specific to you. You need to really consider what you are going to get out of the project and whether or not you can actually accomplish it. Don't pick something too easy or too hard - ideally you are going to learn new things by applying things you already know. Making a game in whatever language you know is a great method of just messing around. Test yourself a bit! Anyone can play a game and so you should be able to show people and they can test and feedback to you. If a game isn't appropriate then pick something which you can imagine the end goal of. If you can picture how the program or website is supposed to look or perform and you have a feeling then you should start thinking about how you should go about programming it. If you've taken any sort of class on programming you will have heard a the phrase "*divide and conquer*". This is essentially the notion of splitting up a large task into smaller, manageable chunks and taking it step by step. On the surface this is just some sort of life lesson. It is only when you think of it in terms of programming that it makes more sense; take any activity your program should be able to fulfil and think about the necessary steps required to make it happen. If you want some style points you should consider the system as a whole and try to group common functionality into classes and functions. If you don't know what I'm on about you should look up ***Object Oriented Programming***. If you really want to get serious or if you are working with other people, consider drawing a diagram of some sort or listing the different parts of your program that need implementing. You can then delegate these tasks to your team or simply visualise your progress as you go. Things like this are also great to post on the readme of your GitHub repository (more on that later) so that people who don't want to trawl through your code have some sort of visual indicator of how the program is coming along. If what your making is a website then make sure to include a link to your website somewhere on the actual readme so that people can look at it. ## Step 3: Staying on Goal To some, programming is hard. To others, it is cruel. While it may be both of these things it can also be neither. It is important to remind yourself why you're programming and to constantly evaluate your progress and interest. If you become bored or dissatisfied then simply look at another field - the beauty of programming is that its a frame of mind; once you have it you can learn something new at an accelerated rate. This section is about how you can stay focused on what you set out to do. What's the point in starting something if you don't reach a point of success somewhere down the line? Having a set of tools that make programming enjoyable and easier are vital for survival. If you need some insight in terms of the programming itself, feel free to check out my other blog posts. Currently, my post [Mistakes, and why you need them](https://blog.aas.sh/Mistakes) is the only other post which talks briefly about what you go through while programming. If in doubt, look what your compiler or your built program is feeding back to you, isolate the code that is making it function that way and fix it. Don't **EVER** let a problem halt a project. If there's any reason to abandon something *don't ever let it be some sort of bug or compiler error*. In face, these are the things you should be craving as you will develop your skills as a programmer, debugger and a researcher all at once. ### 3.1: [Github](http://GitHub.com) I've talked about this previously and I'm going to talk about it again. Any programming enthusiast needs source control and a space on the internet where they can see what they've done. #### What is GitHub anyway? "*GitHub is a development platform inspired by the way you work. From open source to business, you can host and review code, manage projects, and build software alongside millions of other developers.*" In English, GitHub is a space where you can upload coding projects and collaborate with other people easily. Even when working solo having a code repository is crucial. If you make a mistake or if your computer fails then there will always be the last "commit" online. A commit is essentially a snapshot of your program. The reason GitHub is better than something like Dropbox is because of the fact that it is intelligent to notice changes in your code. It only uploads and downloads the new code (a massive time-save with large projects) and summarises the commit with a helpful message along with the lines that have been added and deleted. I'm not going to go too much into this, [so please read this and get started NOW.](https://guides.github.com/activities/hello-world/). Another thing to note is that if you work in multiple places, with multiple people or on multiple machines, being able to download what's new and upload your progress (while automatically merging your work with any made by collaborators) is an amazing routine to get in. It keeps everyone and everything on the same page while also keep a log of every change to the project. #### Why would I want people looking at my code? Firstly, you can make private repositories if you really want to. It requires a subscription to the paid GitHub service, [but students can get this for free](https://education.github.com/pack). I would suggest however, that any project containing non-sensitive info should be public. Why? Well, firstly other people may want to help you out by suggesting fixes, more secure / semantic functions or by simply reporting bugs. Secondly, it will show that you're an active programmer. Anyone (including potential employers) could look at your public repo and see exactly how much progress you've made. If seeing you work on your own projects isn't enough, then ***simply using GitHub can sometimes be a deal-breaker***. Source control is very important to serious developers, the last thing they want is to hire someone with no knowledge of committing to a repo. Don't be worried about people stealing your code. It is much more of a benefit to you to be open and honest about what you have created than it is to be paranoid and making everything you do private. If you're a business or you're planning on monetizing something then make it private, go ahead. But as a small, hobbyist programmer be a little more real and realise that 90% of the people on GitHub could probably make something better anyway - they won't care about stealing your code. Instead, they will help your code become better! If stealing code was a problem then people wouldn't go public with the majority of their repos. #### Why GitHub and not another source control service? Please shut up and just use GitHub. While there are many valid services out there, GitHub is extremely popular and most programmers use it. If you're only looking for source control then maybe looking for a service that offers free private repos would be in your interest, however do not underestimate the importance of others reviewing your code. ### 3.2: Upgrade your setup I cannot stress this enough. Learning the Vi keyboard shortcuts has been a mini-challenge and has helped me enjoy programming even more. Sure, it slowed me down in the beginning but now I am comfortable with navigating any piece of software that supports Vi shortcuts (or Vi emulation plugins) without a mouse. Adobe Brackets, Visual Studio, Google Chrome, GitHub, Googlemail all use / can use Vi shortcuts and it is **FUN**.  [Playing this simple game, Vim Adventures](https://vim-adventures.com/) really helped me get started. The gif I made doesn't really do it justice, but seriously try it out. I didn't understand why it was so popular until I started coding with it and wow am I having fun. Notice I am talking about fun here - it may take a while for me to be productive enough to make this effort worth it, but the fact that I enjoy merely typing is a big boost to my productivity. Why do I keep going on about a text editor? Simple: I enjoy adapting my editor to look and feel cool and unique to me. As I type this it may not be the most amazing [emacs.d](https://github.com/Crysikrend/emacs) it is my own and I'm slowly learning how to make appeal to me. People use emacs as a web browser, as a [note taker](http://orgmode.org/) and as a text editor that can be extended for ***any language***. Trust me, its really neat and if you use Linux or a Mac I'd honestly give it a shot. I will probably make a blog post on how to get started with it, but a bit of googling should help. Note that there are some amazing plugins that allow you to use GitHub within emacs, reinforcing that GitHub is important! If you're on Windows then to be honest you are stuck with Visual Studio for most of your coding needs. I have to admit, you cannot really do much better. If you really wanted to, try using a virtual machine and run a Linux distro so you can see what I'm talking about. You can also look at editors like [Adobe Brackets](http://brackets.io/), [Atom](https://atom.io/) and [Sublime text](https://www.sublimetext.com/) if you're working with code that you don't need an IDE for (Web Development) and you're on Windows. Just in case you didn't know, an IDE is a piece of software that can compile and debug your programs easily in. [Visual Studio](https://www.visualstudio.com/) is probably the best thing on Windows, but there are other IDEs like [Rider by JetBrains](https://www.jetbrains.com/rider/) if you're working with C#. Note that JetBrains have lots of cool IDEs to look at if you want a change to Visual Studio or if you're on a different operating system. If you're doing games development like I am, try a new engine (or if you haven't tried it, try making your own!). When I first opened up [Unreal](https://www.unrealengine.com/) in January I was a little confused, but I slowly learned. After making a game with it I now understand why I enjoy the challenge making a game in pure code. Just a preference, but having more engines under your belt doesn't hurt! ## Step 4: Network Another thing I wanted to mention is how important it is to stay social about your hobby/goals. Tell people what progress you're making and what you want to do next. If they're a programmer also then you can also show them your GitHub repo and talk about how you implemented certain features. Speaking personally, people wanted to know how we made our level 'explode' (shown in the gif in this post). I previously mentioned [Gitter](https://gitter.im/) to be pretty good at getting in touch with people. If you haven't guessed already, it has integration with GitHub! Anyone you speak to on here not only has their own stories, motives and goals but also the repositories to go with them. Find a Gitter room that is related to your project and just chill. There's obviously more than Gitter out there. There's the usual [Reddit](http://reddit.com) for sub-communities, [/g/](http://boards.4chan.org/g/) for discussions and even [Discord servers](discordapp.com) for when you find a community that has one. I am personally in a [Gamesdev Discord](https://discordapp.com/invite/gamedev) and a [Webdev Discord](https://discordapp.com/invite/wdg) and have used both thoroughly. It is important to talk to people - even if you don't know them. You will learn how people who are stronger programmers than you are operate and how they would go about something you're trying to do. I have made a **HUGE** point about GitHub in this article as frankly I'm appalled at how many people on my course do not utilize such a useful tool. Most of the people you talk to will have GitHub profiles so hopefully if I haven't convinced you then the rest of the programming world will. *Seriously, just try it if you haven't already.* ## Step 5: Finishing and Maintaining Not many people choose to do these things, however if you do have a repo on GitHub you should try and make sure you keep a version that is *working as intended* committed. If you want to go in-depth, create a development branch so that any commits you make do not affect the master branch. Then, when you have a new, stable build, commit to the master branch and everyone's happy. The reason I am talking about the end of a project is because it is awfully tempting to abandon a project once you have learned what you can from it. Personally, I have stopped work on [Sprinty](http://github.com/crysikrend/sprinty) ever since Uni started again. It works, sure, but I wish I actually continued it, added new things and ported it to Android like I intended. I am probably never going to actually finish this, but it would be awfully impressive if I did. If I wanted to work with Monogame more, I would, but right now my attention is on [SDL](https://www.libsdl.org/), which is essentially Monogame but C++. If you do manage to finish a project then you should do everything in your power to maintain it. Let's say you made a plugin for some software, or an extension to make a website better - if that website or software changes in some way then your program breaks down. Maybe no one will care, but if someone was to check out your portfolio and find something broken without you giving a good reason on the readme then it may make you out as someone who doesn't test their code thoroughly. ## Wrapping things up I hope this post has been somewhat helpful. I think more people who have programming jobs or who program as part of a university course should try and embrace programming as a hobby as well as a job. I may not be a professional (right now) but apparently I'm pretty good at picking up new things and teaching people what I know, so hopefully now you know just as much as I do about how to get started with doing. If you are really, **really** new to programming and you found this article dissatisfying, let me know. I chose to focus on the people who have some knowledge as its very common for people to create tutorials about the extreme basics of programming - its easy and everyone who programs understands it. The hard thing to talk about is the grey blur between learning about what a function is and how to make a game purely out of code using DirectX, for instance. There are many places out there that will teach you how to code, and I hope that once you have any sort of grasp on it you will think about the things I have talked about and get started with making something for yourself! I have finished Uni for the year and so now have much more free time. My studio, [BestInSlot](http://BestInSlot.gg), got accepted for a placement scheme and so next year we can hopefully develop and market our very own game. Exciting! Keep an eye on my [Twitter](http://twitter.com/crysikrend) for updates and feel free to comment if you need advice on anything I've talked about. Similarly, comment down below if you have found this article helpful as I put quite a lot of time in! Until next time! |
| json metadata | {"tags":["programming","beginners","guide","how","start"],"image":["/content/2017-02/alacrity.gif","/content/2017-04/vimadventures.gif"],"links":["https://blog.aas.sh/posts/2017-04-11-Start-Programming/","https://www.codecademy.com/","https://cs50.harvard.edu/","https://www.edx.org/course/introduction-computer-science-harvardx-cs50x","https://www.codeavengers.com/","http://github.com","https://gitter.im/","http://www.monogame.net/","https://www.ubuntu.com/","https://blog.aas.sh/Mistakes","http://GitHub.com","https://guides.github.com/activities/hello-world/","https://education.github.com/pack","https://vim-adventures.com/","https://github.com/Crysikrend/emacs","http://orgmode.org/","http://brackets.io/","https://atom.io/","https://www.sublimetext.com/","https://www.visualstudio.com/","https://www.jetbrains.com/rider/","https://www.unrealengine.com/","http://reddit.com","http://boards.4chan.org/g/","discordapp.com","https://discordapp.com/invite/gamedev","https://discordapp.com/invite/wdg","http://github.com/crysikrend/sprinty","https://www.libsdl.org/","http://BestInSlot.gg","http://twitter.com/crysikrend"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25411746/Trx aa72e32fbc72fc4c5eaf6bd3dd8f1d3898354500 |
View Raw JSON Data
{
"trx_id": "aa72e32fbc72fc4c5eaf6bd3dd8f1d3898354500",
"block": 25411746,
"trx_in_block": 24,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:28:33",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "programming",
"author": "aas-sh",
"permlink": "6mpge2-start-programming",
"title": "Start Programming",
"body": "> This post can be found on my blog [here.](https://blog.aas.sh/posts/2017-04-11-Start-Programming/)\n\nSo you've been using the internet competently for many years of your life and you've become interested in programming - great! However, you're probably a bit unsure what you should be doing. In this blog post, I hope to inspire you to get in there and just dive into programming and to give you a few tips to get started. Read on!\n\n*This is not going to be programming language specific and nor should it be - instead I hope to talk in a more general sense about how to go about developing a programmer lifestyle.*\n\n## Step 0: Motivation and Goals\nThe first and most important thing to think about when you want to start programming is ***why*** you want to do it. If you are trying to learn how to program purely because then someone else wants you to or if you want a job as a programmer then just be cautious as you will suffer dearly if you try to force yourself into the mindset of a programmer without any real motivation.\n\nThe best motives are things such as:\n- Wanting to build something like an app or website (more on this later)\n- For the pursuit of knowledge and curiosity, to test oneself\n- To understand how something works. How does a website actually appear on your browser?\n\nThis list is not complete in the slightest, nor should you feel deterred by having a reason not mentioned. I am probably missing a lot after all. My point is, you should at some point ***want*** to program. You will stay up late for days on end and spend hours looking at the same pieces of code only to figure out what's wrong and you will hate it. But, it all becomes worth it in the end and the feeling of fulfilment is what keeps you going. There's always some way of solving something, you just need to keep at it. If thinking hard and googling a lot of technical questions and deciphering technical answers doesn't sound fun to you then you're right - its not. What is fun however, is realising that you're learning and that you have benefited from your struggles. Trust me, it is a rewarding hobby (job, whatever).\n\nFinding out why you are wanting to program is the key to unlocking the next step, so please think hard and reflect on your own motives before trying to further yourself.\n\n## Step 1: Getting Started\nNow that you have confirmed that this feels right to you, the next step is to think of a stepping stone towards your goal that is both achievable and interesting to you. I am trying to make this article about recreational programming in the sense that I want to inspire people to program not just for uni or work, but for themselves.\n\nThis step is hard to talk about, so lets break it down a bit:\n\n### 1.1: Beginners: Learning to code\nWe all have to start somewhere, and for the people who have little to no programming skills then this is the place! The fact you are reading this very sentence proves you are nerdy enough to have business with the computing world. After you have read this section make sure you read the other sections too, particularly step 2 onwards which provides advice for everyone.\n\nBelow are a few suggestions on how to get started programming. Think about your goal, do a bit of googling and find what languages you should be learning. **DO NOT try and embark on a big project, whatever you do. The most important thing for you right now is getting knowledge, not projects, under your belt.**\n\n- [Code Academy](https://www.codecademy.com/) for learning the basics of many languages. I highly recommend you at least have a go at a language that you've found to be necessary to meet your goals.\n- [CS50](https://cs50.harvard.edu/) Harvard University allows you to actually audit their computer science course! They allow you to do assignments and watch lectures through [EDX](https://www.edx.org/course/introduction-computer-science-harvardx-cs50x), which is pretty amazing. Be aware that while they may still be working with C it will still be beneficial to you. A lot of knowledge is transferable across languages!\n- Learn through doing. Sure, take out a book from your local library or watch YouTube videos but make sure your fingers are on your keyboard. Trust me, the people who don't type and just sit there during university assignments never learn as much. That's why the above 2 links are great as they are interactive.\n- Google it! Do not be afraid to look up how to do something. After self teaching so much (including how to set up this blog) I can testify that the internet is indeed your friend. Most of the things you learn will be copied from other individuals.\n- [Code Avengers](https://www.codeavengers.com/) is something I have heard but have never tried. I'm just listing it here for completeness.\n\nNote: If you are wanting to learn web development then you need to be more specific. Do you want to learn networking and how to set up the websites in depth, or do you want to be a front end developer (the part of the website people see). If you are interested in the latter then your mind has to be as creative as it is logical and there will be a ***lot*** of competition. Best of luck!\n\nRemember to read the rest of the article to get a feeling of the world of programming. You never know, you might be ready for the next step already!\n\n### 1.2: Knowledgeable: Applying Knowledge\nThis section is for the people who have already learned how to program in some way who either do / have done it as part of an academic course or for work, but do not know how to transfer their skills into something they *want* to do. I like to think this is what sets me apart from some people at my university as I really enjoy working on things in my spare time and I love learning. Sure, we all learn how to program as part of our course, but I'd be lying to say that when we were asked to make a game we didn't stand out. We did pretty well! (work in progress shown below)\n\n\n\nThe key to becoming a better programmer is to actually do something instead of browsing /g/. Same as before, here are a few things you should try out. I'm not going to talk about learning programming, I'm instead going to talk about applying it in different ways.\n\n- Contribute to other people's projects. If you are not familiar with [GitHub](http://github.com) then please read the section coming up. It is *vital* for any programmer to use source control and GitHub is one of the best.\n- Make something. Take a language you know (or you don't know - plot twist!) and try and make something neat. It could be beneficial to mankind or just a proof of concept.\n- Get inspired by others. A lot of programmers blog or have some space on the internet where they show off their achievements. I'm not saying you should feel bad for not achieving much if that's the case, I'm just saying that looking at the success of others can make you feel more productive and give you the nudge you need to become productive.\n- Communicate with other programmers of different skill. Talk to people who are weaker and inspire them and similarly talk to people who are better than you and feel inspired from them. Try [Gitter](https://gitter.im/), a place where programmers can chat and collaborate. For instance, I wanted to learn [MonoGame](http://www.monogame.net/) and so I took to Gitter to ask for advice and if I ever got stuck I had people who enjoyed solving issues.\n- Try Linux. Sounds really stupid I know, but you don't know how many new programmers just use Windows and Visual Studio. Get Linux and start simple with [Ubuntu](https://www.ubuntu.com/) or something. Then, learn Vim or Emacs (I prefer Emacs with Evil Mode - the best of both worlds!). You will learn how to program more efficiently and love using your keyboard over your mouse. Additionally, you will learn how to compile programs without an IDE, how to work a computer with just a terminal (perfect for servers!) and finally why so many people love Linux for programming.\n\n## Step 2: Embarking on a project\nNow you need to consider what you're going to make for the time being. This is going to be different to your end goal and is going to be something specific to you. You need to really consider what you are going to get out of the project and whether or not you can actually accomplish it. Don't pick something too easy or too hard - ideally you are going to learn new things by applying things you already know.\n\nMaking a game in whatever language you know is a great method of just messing around. Test yourself a bit! Anyone can play a game and so you should be able to show people and they can test and feedback to you. If a game isn't appropriate then pick something which you can imagine the end goal of. If you can picture how the program or website is supposed to look or perform and you have a feeling then you should start thinking about how you should go about programming it.\n\nIf you've taken any sort of class on programming you will have heard a the phrase \"*divide and conquer*\". This is essentially the notion of splitting up a large task into smaller, manageable chunks and taking it step by step. On the surface this is just some sort of life lesson. It is only when you think of it in terms of programming that it makes more sense; take any activity your program should be able to fulfil and think about the necessary steps required to make it happen. If you want some style points you should consider the system as a whole and try to group common functionality into classes and functions. If you don't know what I'm on about you should look up ***Object Oriented Programming***.\n\nIf you really want to get serious or if you are working with other people, consider drawing a diagram of some sort or listing the different parts of your program that need implementing. You can then delegate these tasks to your team or simply visualise your progress as you go. Things like this are also great to post on the readme of your GitHub repository (more on that later) so that people who don't want to trawl through your code have some sort of visual indicator of how the program is coming along. If what your making is a website then make sure to include a link to your website somewhere on the actual readme so that people can look at it.\n\n## Step 3: Staying on Goal\nTo some, programming is hard. To others, it is cruel. While it may be both of these things it can also be neither. It is important to remind yourself why you're programming and to constantly evaluate your progress and interest. If you become bored or dissatisfied then simply look at another field - the beauty of programming is that its a frame of mind; once you have it you can learn something new at an accelerated rate.\n\nThis section is about how you can stay focused on what you set out to do. What's the point in starting something if you don't reach a point of success somewhere down the line? Having a set of tools that make programming enjoyable and easier are vital for survival.\n\nIf you need some insight in terms of the programming itself, feel free to check out my other blog posts. Currently, my post [Mistakes, and why you need them](https://blog.aas.sh/Mistakes) is the only other post which talks briefly about what you go through while programming. If in doubt, look what your compiler or your built program is feeding back to you, isolate the code that is making it function that way and fix it. Don't **EVER** let a problem halt a project. If there's any reason to abandon something *don't ever let it be some sort of bug or compiler error*. In face, these are the things you should be craving as you will develop your skills as a programmer, debugger and a researcher all at once.\n\n### 3.1: [Github](http://GitHub.com)\nI've talked about this previously and I'm going to talk about it again. Any programming enthusiast needs source control and a space on the internet where they can see what they've done.\n\n#### What is GitHub anyway?\n\"*GitHub is a development platform inspired by the way you work. From open source to business, you can host and review code, manage projects, and build software alongside millions of other developers.*\" In English, GitHub is a space where you can upload coding projects and collaborate with other people easily. Even when working solo having a code repository is crucial. If you make a mistake or if your computer fails then there will always be the last \"commit\" online.\n\nA commit is essentially a snapshot of your program. The reason GitHub is better than something like Dropbox is because of the fact that it is intelligent to notice changes in your code. It only uploads and downloads the new code (a massive time-save with large projects) and summarises the commit with a helpful message along with the lines that have been added and deleted. I'm not going to go too much into this, [so please read this and get started NOW.](https://guides.github.com/activities/hello-world/).\n\nAnother thing to note is that if you work in multiple places, with multiple people or on multiple machines, being able to download what's new and upload your progress (while automatically merging your work with any made by collaborators) is an amazing routine to get in. It keeps everyone and everything on the same page while also keep a log of every change to the project.\n\n#### Why would I want people looking at my code?\nFirstly, you can make private repositories if you really want to. It requires a subscription to the paid GitHub service, [but students can get this for free](https://education.github.com/pack). I would suggest however, that any project containing non-sensitive info should be public. Why? Well, firstly other people may want to help you out by suggesting fixes, more secure / semantic functions or by simply reporting bugs. Secondly, it will show that you're an active programmer. Anyone (including potential employers) could look at your public repo and see exactly how much progress you've made.\n\nIf seeing you work on your own projects isn't enough, then ***simply using GitHub can sometimes be a deal-breaker***. Source control is very important to serious developers, the last thing they want is to hire someone with no knowledge of committing to a repo.\n\nDon't be worried about people stealing your code. It is much more of a benefit to you to be open and honest about what you have created than it is to be paranoid and making everything you do private. If you're a business or you're planning on monetizing something then make it private, go ahead. But as a small, hobbyist programmer be a little more real and realise that 90% of the people on GitHub could probably make something better anyway - they won't care about stealing your code. Instead, they will help your code become better! If stealing code was a problem then people wouldn't go public with the majority of their repos.\n\n#### Why GitHub and not another source control service?\nPlease shut up and just use GitHub. While there are many valid services out there, GitHub is extremely popular and most programmers use it. If you're only looking for source control then maybe looking for a service that offers free private repos would be in your interest, however do not underestimate the importance of others reviewing your code.\n\n### 3.2: Upgrade your setup\nI cannot stress this enough. Learning the Vi keyboard shortcuts has been a mini-challenge and has helped me enjoy programming even more. Sure, it slowed me down in the beginning but now I am comfortable with navigating any piece of software that supports Vi shortcuts (or Vi emulation plugins) without a mouse. Adobe Brackets, Visual Studio, Google Chrome, GitHub, Googlemail all use / can use Vi shortcuts and it is **FUN**.\n\n\n\n[Playing this simple game, Vim Adventures](https://vim-adventures.com/) really helped me get started. The gif I made doesn't really do it justice, but seriously try it out. I didn't understand why it was so popular until I started coding with it and wow am I having fun. Notice I am talking about fun here - it may take a while for me to be productive enough to make this effort worth it, but the fact that I enjoy merely typing is a big boost to my productivity.\n\nWhy do I keep going on about a text editor? Simple: I enjoy adapting my editor to look and feel cool and unique to me. As I type this it may not be the most amazing [emacs.d](https://github.com/Crysikrend/emacs) it is my own and I'm slowly learning how to make appeal to me. People use emacs as a web browser, as a [note taker](http://orgmode.org/) and as a text editor that can be extended for ***any language***. Trust me, its really neat and if you use Linux or a Mac I'd honestly give it a shot. I will probably make a blog post on how to get started with it, but a bit of googling should help. Note that there are some amazing plugins that allow you to use GitHub within emacs, reinforcing that GitHub is important!\n\nIf you're on Windows then to be honest you are stuck with Visual Studio for most of your coding needs. I have to admit, you cannot really do much better. If you really wanted to, try using a virtual machine and run a Linux distro so you can see what I'm talking about. You can also look at editors like [Adobe Brackets](http://brackets.io/), [Atom](https://atom.io/) and [Sublime text](https://www.sublimetext.com/) if you're working with code that you don't need an IDE for (Web Development) and you're on Windows.\n\nJust in case you didn't know, an IDE is a piece of software that can compile and debug your programs easily in. [Visual Studio](https://www.visualstudio.com/) is probably the best thing on Windows, but there are other IDEs like [Rider by JetBrains](https://www.jetbrains.com/rider/) if you're working with C#. Note that JetBrains have lots of cool IDEs to look at if you want a change to Visual Studio or if you're on a different operating system.\n\nIf you're doing games development like I am, try a new engine (or if you haven't tried it, try making your own!). When I first opened up [Unreal](https://www.unrealengine.com/) in January I was a little confused, but I slowly learned. After making a game with it I now understand why I enjoy the challenge making a game in pure code. Just a preference, but having more engines under your belt doesn't hurt!\n\n## Step 4: Network\nAnother thing I wanted to mention is how important it is to stay social about your hobby/goals. Tell people what progress you're making and what you want to do next. If they're a programmer also then you can also show them your GitHub repo and talk about how you implemented certain features. Speaking personally, people wanted to know how we made our level 'explode' (shown in the gif in this post).\n\nI previously mentioned [Gitter](https://gitter.im/) to be pretty good at getting in touch with people. If you haven't guessed already, it has integration with GitHub! Anyone you speak to on here not only has their own stories, motives and goals but also the repositories to go with them. Find a Gitter room that is related to your project and just chill.\n\nThere's obviously more than Gitter out there. There's the usual [Reddit](http://reddit.com) for sub-communities, [/g/](http://boards.4chan.org/g/) for discussions and even [Discord servers](discordapp.com) for when you find a community that has one. I am personally in a [Gamesdev Discord](https://discordapp.com/invite/gamedev) and a [Webdev Discord](https://discordapp.com/invite/wdg) and have used both thoroughly.\n\nIt is important to talk to people - even if you don't know them. You will learn how people who are stronger programmers than you are operate and how they would go about something you're trying to do. I have made a **HUGE** point about GitHub in this article as frankly I'm appalled at how many people on my course do not utilize such a useful tool. Most of the people you talk to will have GitHub profiles so hopefully if I haven't convinced you then the rest of the programming world will. *Seriously, just try it if you haven't already.*\n\n## Step 5: Finishing and Maintaining\nNot many people choose to do these things, however if you do have a repo on GitHub you should try and make sure you keep a version that is *working as intended* committed. If you want to go in-depth, create a development branch so that any commits you make do not affect the master branch. Then, when you have a new, stable build, commit to the master branch and everyone's happy.\n\nThe reason I am talking about the end of a project is because it is awfully tempting to abandon a project once you have learned what you can from it. Personally, I have stopped work on [Sprinty](http://github.com/crysikrend/sprinty) ever since Uni started again. It works, sure, but I wish I actually continued it, added new things and ported it to Android like I intended. I am probably never going to actually finish this, but it would be awfully impressive if I did. If I wanted to work with Monogame more, I would, but right now my attention is on [SDL](https://www.libsdl.org/), which is essentially Monogame but C++.\n\nIf you do manage to finish a project then you should do everything in your power to maintain it. Let's say you made a plugin for some software, or an extension to make a website better - if that website or software changes in some way then your program breaks down. Maybe no one will care, but if someone was to check out your portfolio and find something broken without you giving a good reason on the readme then it may make you out as someone who doesn't test their code thoroughly.\n\n## Wrapping things up\nI hope this post has been somewhat helpful. I think more people who have programming jobs or who program as part of a university course should try and embrace programming as a hobby as well as a job. I may not be a professional (right now) but apparently I'm pretty good at picking up new things and teaching people what I know, so hopefully now you know just as much as I do about how to get started with doing.\n\nIf you are really, **really** new to programming and you found this article dissatisfying, let me know. I chose to focus on the people who have some knowledge as its very common for people to create tutorials about the extreme basics of programming - its easy and everyone who programs understands it. The hard thing to talk about is the grey blur between learning about what a function is and how to make a game purely out of code using DirectX, for instance. There are many places out there that will teach you how to code, and I hope that once you have any sort of grasp on it you will think about the things I have talked about and get started with making something for yourself!\n\nI have finished Uni for the year and so now have much more free time. My studio, [BestInSlot](http://BestInSlot.gg), got accepted for a placement scheme and so next year we can hopefully develop and market our very own game. Exciting!\n\nKeep an eye on my [Twitter](http://twitter.com/crysikrend) for updates and feel free to comment if you need advice on anything I've talked about. Similarly, comment down below if you have found this article helpful as I put quite a lot of time in!\n\nUntil next time!",
"json_metadata": "{\"tags\":[\"programming\",\"beginners\",\"guide\",\"how\",\"start\"],\"image\":[\"/content/2017-02/alacrity.gif\",\"/content/2017-04/vimadventures.gif\"],\"links\":[\"https://blog.aas.sh/posts/2017-04-11-Start-Programming/\",\"https://www.codecademy.com/\",\"https://cs50.harvard.edu/\",\"https://www.edx.org/course/introduction-computer-science-harvardx-cs50x\",\"https://www.codeavengers.com/\",\"http://github.com\",\"https://gitter.im/\",\"http://www.monogame.net/\",\"https://www.ubuntu.com/\",\"https://blog.aas.sh/Mistakes\",\"http://GitHub.com\",\"https://guides.github.com/activities/hello-world/\",\"https://education.github.com/pack\",\"https://vim-adventures.com/\",\"https://github.com/Crysikrend/emacs\",\"http://orgmode.org/\",\"http://brackets.io/\",\"https://atom.io/\",\"https://www.sublimetext.com/\",\"https://www.visualstudio.com/\",\"https://www.jetbrains.com/rider/\",\"https://www.unrealengine.com/\",\"http://reddit.com\",\"http://boards.4chan.org/g/\",\"discordapp.com\",\"https://discordapp.com/invite/gamedev\",\"https://discordapp.com/invite/wdg\",\"http://github.com/crysikrend/sprinty\",\"https://www.libsdl.org/\",\"http://BestInSlot.gg\",\"http://twitter.com/crysikrend\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}aas-shflagged (-100.00%) @aas-sh / start-programming2018/08/26 17:26:27
aas-shflagged (-100.00%) @aas-sh / start-programming
2018/08/26 17:26:27
| voter | aas-sh |
| author | aas-sh |
| permlink | start-programming |
| weight | -10000 (-100.00%) |
| Transaction Info | Block #25411704/Trx 28ba096cdf9e4a663fb58591a45a40a5eb34c875 |
View Raw JSON Data
{
"trx_id": "28ba096cdf9e4a663fb58591a45a40a5eb34c875",
"block": 25411704,
"trx_in_block": 23,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:26:27",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "aas-sh",
"permlink": "start-programming",
"weight": -10000
}
]
}aas-shremoved vote from (0.00%) @aas-sh / start-programming2018/08/26 17:26:21
aas-shremoved vote from (0.00%) @aas-sh / start-programming
2018/08/26 17:26:21
| voter | aas-sh |
| author | aas-sh |
| permlink | start-programming |
| weight | 0 (0.00%) |
| Transaction Info | Block #25411702/Trx fe4776e414ed09067d06becebfe10bccd5c0edda |
View Raw JSON Data
{
"trx_id": "fe4776e414ed09067d06becebfe10bccd5c0edda",
"block": 25411702,
"trx_in_block": 16,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:26:21",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "aas-sh",
"permlink": "start-programming",
"weight": 0
}
]
}aas-shflagged (-100.00%) @aas-sh / what-even-is-haskell2018/08/26 17:26:12
aas-shflagged (-100.00%) @aas-sh / what-even-is-haskell
2018/08/26 17:26:12
| voter | aas-sh |
| author | aas-sh |
| permlink | what-even-is-haskell |
| weight | -10000 (-100.00%) |
| Transaction Info | Block #25411699/Trx ae257431d3c4fdf02a4a40aa0a65f8ba59bb057c |
View Raw JSON Data
{
"trx_id": "ae257431d3c4fdf02a4a40aa0a65f8ba59bb057c",
"block": 25411699,
"trx_in_block": 33,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:26:12",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "aas-sh",
"permlink": "what-even-is-haskell",
"weight": -10000
}
]
}aas-shremoved vote from (0.00%) @aas-sh / what-even-is-haskell2018/08/26 17:26:06
aas-shremoved vote from (0.00%) @aas-sh / what-even-is-haskell
2018/08/26 17:26:06
| voter | aas-sh |
| author | aas-sh |
| permlink | what-even-is-haskell |
| weight | 0 (0.00%) |
| Transaction Info | Block #25411697/Trx 529ff42227c5351f88f4534cb187d84b033dfd02 |
View Raw JSON Data
{
"trx_id": "529ff42227c5351f88f4534cb187d84b033dfd02",
"block": 25411697,
"trx_in_block": 12,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:26:06",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "aas-sh",
"permlink": "what-even-is-haskell",
"weight": 0
}
]
}aas-shupdated their account properties2018/08/26 17:24:48
aas-shupdated their account properties
2018/08/26 17:24:48
| account | aas-sh |
| memo key | STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6 |
| json metadata | {"profile":{"cover_image":"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg","name":"Ashe","about":"Ambitious CS Student and indie games developer","location":"Sheffield, UK","website":"https://aas.sh","profile_image":"https://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg"}} |
| Transaction Info | Block #25411671/Trx fce51c73fdcdc76c257d3976581d56d59c095828 |
View Raw JSON Data
{
"trx_id": "fce51c73fdcdc76c257d3976581d56d59c095828",
"block": 25411671,
"trx_in_block": 52,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:24:48",
"op": [
"account_update",
{
"account": "aas-sh",
"memo_key": "STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6",
"json_metadata": "{\"profile\":{\"cover_image\":\"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg\",\"name\":\"Ashe\",\"about\":\"Ambitious CS Student and indie games developer\",\"location\":\"Sheffield, UK\",\"website\":\"https://aas.sh\",\"profile_image\":\"https://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg\"}}"
}
]
}aas-shupdated their account properties2018/08/26 17:24:36
aas-shupdated their account properties
2018/08/26 17:24:36
| account | aas-sh |
| memo key | STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6 |
| json metadata | {"profile":{"cover_image":"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg","name":"Ashe","about":"Ambitious CS Student and indie games developer","location":"Sheffield, UK","website":"https://aas.sh"}} |
| Transaction Info | Block #25411667/Trx 0a21e9d7e838a70f9487ac436fc2cb87ba5499a1 |
View Raw JSON Data
{
"trx_id": "0a21e9d7e838a70f9487ac436fc2cb87ba5499a1",
"block": 25411667,
"trx_in_block": 64,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:24:36",
"op": [
"account_update",
{
"account": "aas-sh",
"memo_key": "STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6",
"json_metadata": "{\"profile\":{\"cover_image\":\"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg\",\"name\":\"Ashe\",\"about\":\"Ambitious CS Student and indie games developer\",\"location\":\"Sheffield, UK\",\"website\":\"https://aas.sh\"}}"
}
]
}aas-shupdated their account properties2018/08/26 17:24:21
aas-shupdated their account properties
2018/08/26 17:24:21
| account | aas-sh |
| memo key | STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6 |
| json metadata | {"profile":{"profile_image":"http://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg","cover_image":"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg","name":"Ashe","about":"Ambitious CS Student and indie games developer","location":"Sheffield, UK","website":"https://aas.sh"}} |
| Transaction Info | Block #25411662/Trx 58b5d949106d3cd4c608916858644a0b3ab79370 |
View Raw JSON Data
{
"trx_id": "58b5d949106d3cd4c608916858644a0b3ab79370",
"block": 25411662,
"trx_in_block": 19,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:24:21",
"op": [
"account_update",
{
"account": "aas-sh",
"memo_key": "STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6",
"json_metadata": "{\"profile\":{\"profile_image\":\"http://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg\",\"cover_image\":\"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg\",\"name\":\"Ashe\",\"about\":\"Ambitious CS Student and indie games developer\",\"location\":\"Sheffield, UK\",\"website\":\"https://aas.sh\"}}"
}
]
}aas-shupdated their account properties2018/08/26 17:23:54
aas-shupdated their account properties
2018/08/26 17:23:54
| account | aas-sh |
| memo key | STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6 |
| json metadata | {"profile":{"profile_image":"https://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg","cover_image":"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg","name":"Ashe","about":"Ambitious CS Student and indie games developer","location":"Sheffield, UK","website":"https://aas.sh"}} |
| Transaction Info | Block #25411653/Trx 46f4d3110a9865146c6727b1bba4c89f0d6ef02e |
View Raw JSON Data
{
"trx_id": "46f4d3110a9865146c6727b1bba4c89f0d6ef02e",
"block": 25411653,
"trx_in_block": 29,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-26T17:23:54",
"op": [
"account_update",
{
"account": "aas-sh",
"memo_key": "STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6",
"json_metadata": "{\"profile\":{\"profile_image\":\"https://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg\",\"cover_image\":\"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg\",\"name\":\"Ashe\",\"about\":\"Ambitious CS Student and indie games developer\",\"location\":\"Sheffield, UK\",\"website\":\"https://aas.sh\"}}"
}
]
}aas-shreceived 0.032 STEEM, 0.041 SP author reward for @aas-sh / start-programming2018/08/23 11:00:33
aas-shreceived 0.032 STEEM, 0.041 SP author reward for @aas-sh / start-programming
2018/08/23 11:00:33
| author | aas-sh |
| permlink | start-programming |
| sbd payout | 0.000 SBD |
| steem payout | 0.032 STEEM |
| vesting payout | 66.802480 VESTS |
| Transaction Info | Block #25317650/Virtual Operation #29 |
View Raw JSON Data
{
"trx_id": "0000000000000000000000000000000000000000",
"block": 25317650,
"trx_in_block": 4294967295,
"op_in_trx": 0,
"virtual_op": 29,
"timestamp": "2018-08-23T11:00:33",
"op": [
"author_reward",
{
"author": "aas-sh",
"permlink": "start-programming",
"sbd_payout": "0.000 SBD",
"steem_payout": "0.032 STEEM",
"vesting_payout": "66.802480 VESTS"
}
]
}aas-shpublished a new post: start-programming2018/08/16 16:28:42
aas-shpublished a new post: start-programming
2018/08/16 16:28:42
| parent author | |
| parent permlink | programming |
| author | aas-sh |
| permlink | start-programming |
| title | Deleted |
| body | Deleted |
| json metadata | {"tags":["spam","programming"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25122675/Trx 0e05133e8f29eee96e13e0f1f5f7ddfb820d802f |
View Raw JSON Data
{
"trx_id": "0e05133e8f29eee96e13e0f1f5f7ddfb820d802f",
"block": 25122675,
"trx_in_block": 19,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T16:28:42",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "programming",
"author": "aas-sh",
"permlink": "start-programming",
"title": "Deleted",
"body": "Deleted",
"json_metadata": "{\"tags\":[\"spam\",\"programming\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}fastresteemupvoted (1.00%) @aas-sh / what-even-is-haskell2018/08/16 16:28:42
fastresteemupvoted (1.00%) @aas-sh / what-even-is-haskell
2018/08/16 16:28:42
| voter | fastresteem |
| author | aas-sh |
| permlink | what-even-is-haskell |
| weight | 100 (1.00%) |
| Transaction Info | Block #25122675/Trx 5d39e3f51cf6ddd78d75eb0c5c1d7d46f164778f |
View Raw JSON Data
{
"trx_id": "5d39e3f51cf6ddd78d75eb0c5c1d7d46f164778f",
"block": 25122675,
"trx_in_block": 6,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T16:28:42",
"op": [
"vote",
{
"voter": "fastresteem",
"author": "aas-sh",
"permlink": "what-even-is-haskell",
"weight": 100
}
]
}aas-shpublished a new post: what-even-is-haskell2018/08/16 16:28:15
aas-shpublished a new post: what-even-is-haskell
2018/08/16 16:28:15
| parent author | |
| parent permlink | haskell |
| author | aas-sh |
| permlink | what-even-is-haskell |
| title | Deleted |
| body | Deleted |
| json metadata | {"tags":["spam","haskell"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25122666/Trx 1066db91aa2c22ad4ced5039199ab41373c4ccd4 |
View Raw JSON Data
{
"trx_id": "1066db91aa2c22ad4ced5039199ab41373c4ccd4",
"block": 25122666,
"trx_in_block": 10,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T16:28:15",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "haskell",
"author": "aas-sh",
"permlink": "what-even-is-haskell",
"title": "Deleted",
"body": "Deleted",
"json_metadata": "{\"tags\":[\"spam\",\"haskell\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}aas-shupdated their account properties2018/08/16 16:27:18
aas-shupdated their account properties
2018/08/16 16:27:18
| account | aas-sh |
| memo key | STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6 |
| json metadata | {"profile":{"profile_image":"https://cdn.steemitimages.com/DQmcYRwTk3cWA7WfmKsj9qvYdPbjrDn4F7BVZTPWMoKG5bw/romain-briaux-167.jpg"}} |
| Transaction Info | Block #25122647/Trx 455385db2a4f40340bcbfab1a0aeeaaab38b2228 |
View Raw JSON Data
{
"trx_id": "455385db2a4f40340bcbfab1a0aeeaaab38b2228",
"block": 25122647,
"trx_in_block": 48,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T16:27:18",
"op": [
"account_update",
{
"account": "aas-sh",
"memo_key": "STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6",
"json_metadata": "{\"profile\":{\"profile_image\":\"https://cdn.steemitimages.com/DQmcYRwTk3cWA7WfmKsj9qvYdPbjrDn4F7BVZTPWMoKG5bw/romain-briaux-167.jpg\"}}"
}
]
}aas-shupdated their account properties2018/08/16 16:26:27
aas-shupdated their account properties
2018/08/16 16:26:27
| account | aas-sh |
| memo key | STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6 |
| json metadata | {"profile":{"profile_image":"https://cdn.steemitimages.com/DQmeSB9S3v781ApTMY6Gcr3iovEv8S4JJjho8P1htRzNDTz/stefan-stefancik-105376.jpg"}} |
| Transaction Info | Block #25122630/Trx 26063d8c278ff2c26eb87576fc79478155f3bfac |
View Raw JSON Data
{
"trx_id": "26063d8c278ff2c26eb87576fc79478155f3bfac",
"block": 25122630,
"trx_in_block": 26,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T16:26:27",
"op": [
"account_update",
{
"account": "aas-sh",
"memo_key": "STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6",
"json_metadata": "{\"profile\":{\"profile_image\":\"https://cdn.steemitimages.com/DQmeSB9S3v781ApTMY6Gcr3iovEv8S4JJjho8P1htRzNDTz/stefan-stefancik-105376.jpg\"}}"
}
]
}aas-shpublished a new post: what-even-is-haskell2018/08/16 12:12:15
aas-shpublished a new post: what-even-is-haskell
2018/08/16 12:12:15
| parent author | |
| parent permlink | haskell |
| author | aas-sh |
| permlink | what-even-is-haskell |
| title | What even is Haskell? |
| body | @@ -1,16 +1,122 @@ +%3E This post can be found on my website %5Bhere.%5D(https://blog.aas.sh/2018/03/18/What-Even-Is-Haskell.html)%0A%0A You may have not |
| json metadata | {"tags":["programming","haskell","beginners","guide","functional"],"links":["https://blog.aas.sh/2018/03/18/What-Even-Is-Haskell.html","https://wiki.haskell.org/Introduction","https://haskell.org","https://wiki.haskell.org/Polymorphism","https://wiki.haskell.org/Typing","https://wiki.haskell.org/Lazy_evaluation","https://wiki.haskell.org/Functional_programming","https://en.wikipedia.org/wiki/Imperative_programming","https://en.wikipedia.org/wiki/Object-oriented_programming","https://en.wikipedia.org/wiki/Procedural_programming","https://en.wikipedia.org/wiki/Parallel_computing","https://en.wikipedia.org/wiki/Immutable_object","https://en.wikipedia.org/wiki/Strong_and_weak_typing","http://www.wowhead.com/spell=118/polymorph","http://hackage.haskell.org/package/base-4.11.0.0/docs/Prelude.html#t:Num","http://learnyouahaskell.com/","http://haskellbook.com/","https://www.youtube.com/channel/UC9-y-6csu5WGm29I7JiwpnA","http://webchat.freenode.net/?channels=haskell","https://discord.me/fp","https://twitter.com/crysikrend"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25117548/Trx cbca015a8aa4cbca8e2b44c3a2b9fc8db8e1072b |
View Raw JSON Data
{
"trx_id": "cbca015a8aa4cbca8e2b44c3a2b9fc8db8e1072b",
"block": 25117548,
"trx_in_block": 15,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T12:12:15",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "haskell",
"author": "aas-sh",
"permlink": "what-even-is-haskell",
"title": "What even is Haskell?",
"body": "@@ -1,16 +1,122 @@\n+%3E This post can be found on my website %5Bhere.%5D(https://blog.aas.sh/2018/03/18/What-Even-Is-Haskell.html)%0A%0A\n You may have not\n",
"json_metadata": "{\"tags\":[\"programming\",\"haskell\",\"beginners\",\"guide\",\"functional\"],\"links\":[\"https://blog.aas.sh/2018/03/18/What-Even-Is-Haskell.html\",\"https://wiki.haskell.org/Introduction\",\"https://haskell.org\",\"https://wiki.haskell.org/Polymorphism\",\"https://wiki.haskell.org/Typing\",\"https://wiki.haskell.org/Lazy_evaluation\",\"https://wiki.haskell.org/Functional_programming\",\"https://en.wikipedia.org/wiki/Imperative_programming\",\"https://en.wikipedia.org/wiki/Object-oriented_programming\",\"https://en.wikipedia.org/wiki/Procedural_programming\",\"https://en.wikipedia.org/wiki/Parallel_computing\",\"https://en.wikipedia.org/wiki/Immutable_object\",\"https://en.wikipedia.org/wiki/Strong_and_weak_typing\",\"http://www.wowhead.com/spell=118/polymorph\",\"http://hackage.haskell.org/package/base-4.11.0.0/docs/Prelude.html#t:Num\",\"http://learnyouahaskell.com/\",\"http://haskellbook.com/\",\"https://www.youtube.com/channel/UC9-y-6csu5WGm29I7JiwpnA\",\"http://webchat.freenode.net/?channels=haskell\",\"https://discord.me/fp\",\"https://twitter.com/crysikrend\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}aas-shpublished a new post: start-programming2018/08/16 12:09:54
aas-shpublished a new post: start-programming
2018/08/16 12:09:54
| parent author | |
| parent permlink | programming |
| author | aas-sh |
| permlink | start-programming |
| title | Start Programming! |
| body | @@ -1,8 +1,111 @@ +%3E This post can be found on my website %5Bhere.%5D(https://blog.aas.sh/2017/04/11/Start-Programming.html)%0A%0A So you'v |
| json metadata | {"tags":["programming","beginners","guide","how","start"],"image":["https://cdn.steemitimages.com/DQmVuMeXL29Get5kB6p684bxbajVtraMe1p2DiY2CcRLJZg/alacrity.gif","https://cdn.steemitimages.com/DQmPnsaQYvJfNho7FAxtFzqc1m7bFhjzsvy4AL8Sf3XgJi6/vimadventures.gif"],"links":["https://blog.aas.sh/2017/04/11/Start-Programming.html","https://www.codecademy.com/","https://cs50.harvard.edu/","https://www.edx.org/course/introduction-computer-science-harvardx-cs50x","https://www.codeavengers.com/","http://github.com","https://gitter.im/","http://www.monogame.net/","https://www.ubuntu.com/","https://blog.aas.sh/Mistakes","http://GitHub.com","https://guides.github.com/activities/hello-world/","https://education.github.com/pack","https://vim-adventures.com/","https://github.com/Crysikrend/emacs","http://orgmode.org/","http://brackets.io/","https://atom.io/","https://www.sublimetext.com/","https://www.visualstudio.com/","https://www.jetbrains.com/rider/","https://www.unrealengine.com/","http://reddit.com","http://boards.4chan.org/g/","discordapp.com","https://discordapp.com/invite/gamedev","https://discordapp.com/invite/wdg","http://github.com/crysikrend/sprinty","https://www.libsdl.org/","http://BestInSlot.gg","http://twitter.com/crysikrend"],"app":"steemit/0.1","format":"markdown"} |
| Transaction Info | Block #25117501/Trx 31a688b4a8cd739f30a73cc31e784e63534d00f0 |
View Raw JSON Data
{
"trx_id": "31a688b4a8cd739f30a73cc31e784e63534d00f0",
"block": 25117501,
"trx_in_block": 2,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T12:09:54",
"op": [
"comment",
{
"parent_author": "",
"parent_permlink": "programming",
"author": "aas-sh",
"permlink": "start-programming",
"title": "Start Programming!",
"body": "@@ -1,8 +1,111 @@\n+%3E This post can be found on my website %5Bhere.%5D(https://blog.aas.sh/2017/04/11/Start-Programming.html)%0A%0A\n So you'v\n",
"json_metadata": "{\"tags\":[\"programming\",\"beginners\",\"guide\",\"how\",\"start\"],\"image\":[\"https://cdn.steemitimages.com/DQmVuMeXL29Get5kB6p684bxbajVtraMe1p2DiY2CcRLJZg/alacrity.gif\",\"https://cdn.steemitimages.com/DQmPnsaQYvJfNho7FAxtFzqc1m7bFhjzsvy4AL8Sf3XgJi6/vimadventures.gif\"],\"links\":[\"https://blog.aas.sh/2017/04/11/Start-Programming.html\",\"https://www.codecademy.com/\",\"https://cs50.harvard.edu/\",\"https://www.edx.org/course/introduction-computer-science-harvardx-cs50x\",\"https://www.codeavengers.com/\",\"http://github.com\",\"https://gitter.im/\",\"http://www.monogame.net/\",\"https://www.ubuntu.com/\",\"https://blog.aas.sh/Mistakes\",\"http://GitHub.com\",\"https://guides.github.com/activities/hello-world/\",\"https://education.github.com/pack\",\"https://vim-adventures.com/\",\"https://github.com/Crysikrend/emacs\",\"http://orgmode.org/\",\"http://brackets.io/\",\"https://atom.io/\",\"https://www.sublimetext.com/\",\"https://www.visualstudio.com/\",\"https://www.jetbrains.com/rider/\",\"https://www.unrealengine.com/\",\"http://reddit.com\",\"http://boards.4chan.org/g/\",\"discordapp.com\",\"https://discordapp.com/invite/gamedev\",\"https://discordapp.com/invite/wdg\",\"http://github.com/crysikrend/sprinty\",\"https://www.libsdl.org/\",\"http://BestInSlot.gg\",\"http://twitter.com/crysikrend\"],\"app\":\"steemit/0.1\",\"format\":\"markdown\"}"
}
]
}aas-shupvoted (100.00%) @aas-sh / start-programming2018/08/16 12:07:18
aas-shupvoted (100.00%) @aas-sh / start-programming
2018/08/16 12:07:18
| voter | aas-sh |
| author | aas-sh |
| permlink | start-programming |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25117449/Trx 2c5279dab15e6fdfb2d802eea9a4e0256b5263a7 |
View Raw JSON Data
{
"trx_id": "2c5279dab15e6fdfb2d802eea9a4e0256b5263a7",
"block": 25117449,
"trx_in_block": 1,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T12:07:18",
"op": [
"vote",
{
"voter": "aas-sh",
"author": "aas-sh",
"permlink": "start-programming",
"weight": 10000
}
]
}sensationupvoted (100.00%) @aas-sh / start-programming2018/08/16 11:55:36
sensationupvoted (100.00%) @aas-sh / start-programming
2018/08/16 11:55:36
| voter | sensation |
| author | aas-sh |
| permlink | start-programming |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25117215/Trx 3f444d87bcc9dd87bcc2c4e24716c67042551fe8 |
View Raw JSON Data
{
"trx_id": "3f444d87bcc9dd87bcc2c4e24716c67042551fe8",
"block": 25117215,
"trx_in_block": 17,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T11:55:36",
"op": [
"vote",
{
"voter": "sensation",
"author": "aas-sh",
"permlink": "start-programming",
"weight": 10000
}
]
}sensationupvoted (100.00%) @aas-sh / what-even-is-haskell2018/08/16 11:55:00
sensationupvoted (100.00%) @aas-sh / what-even-is-haskell
2018/08/16 11:55:00
| voter | sensation |
| author | aas-sh |
| permlink | what-even-is-haskell |
| weight | 10000 (100.00%) |
| Transaction Info | Block #25117203/Trx 921aa6e855677dcc9dd985e7ad55298cace8069a |
View Raw JSON Data
{
"trx_id": "921aa6e855677dcc9dd985e7ad55298cace8069a",
"block": 25117203,
"trx_in_block": 61,
"op_in_trx": 0,
"virtual_op": 0,
"timestamp": "2018-08-16T11:55:00",
"op": [
"vote",
{
"voter": "sensation",
"author": "aas-sh",
"permlink": "what-even-is-haskell",
"weight": 10000
}
]
}Manabar
Voting Power100.00%
Downvote Power100.00%
Resource Credits100.00%
Reputation Progress0.00%
{
"voting_manabar": {
"current_mana": "8143659806",
"last_update_time": 1779050811
},
"downvote_manabar": {
"current_mana": 2035914951,
"last_update_time": 1779050811
},
"rc_account": {
"account": "aas-sh",
"rc_manabar": {
"current_mana": "10164408779",
"last_update_time": 1779050811
},
"max_rc_creation_adjustment": {
"amount": "2020748973",
"precision": 6,
"nai": "@@000000037"
},
"max_rc": "10164408779"
}
}Account Metadata
| POSTING JSON METADATA | |
| profile | {"name":"Ashe","website":"https://aas.sh","version":2} |
| JSON METADATA | |
| profile | {"cover_image":"https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg","name":"Ashe","about":"Ambitious CS Student and indie games developer","location":"Sheffield, UK","website":"https://aas.sh","profile_image":"https://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg"} |
{
"posting_json_metadata": {
"profile": {
"name": "Ashe",
"website": "https://aas.sh",
"version": 2
}
},
"json_metadata": {
"profile": {
"cover_image": "https://cdn.steemitimages.com/DQmT23SvT9yu3oHCyZo1gQuoVbf4SrDPQg2GvJWNvkN7tnY/anton-sharov-133632.jpg",
"name": "Ashe",
"about": "Ambitious CS Student and indie games developer",
"location": "Sheffield, UK",
"website": "https://aas.sh",
"profile_image": "https://cdn.steemitimages.com/DQmX1DT8DG5iUxcanJE6dJ2kp19mf25kxxbF13TVCc5fTT1/2qrrLmg2_400x400.jpg"
}
}
}Auth Keys
Owner
Single Signature
Public Keys
STM8cWUTvpJwtKkvLJ5AQ5iKZhFWJBKBdAUXub6nr2RZ7vRcFKPzR1/1
Active
Single Signature
Public Keys
STM5gXLneWqCr3hiUEcRUfgWBo8U4ktdbF8hLvqctqMB9ZznNNJJA1/1
Posting
Single Signature
Public Keys
STM8eaB64qVgR4N7do5HVZVxPPg6afRt4ZcMQ3DY989zS9f4LxrdD1/1
App Permissions
@finally.app1/1
Memo
STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6
{
"owner": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM8cWUTvpJwtKkvLJ5AQ5iKZhFWJBKBdAUXub6nr2RZ7vRcFKPzR",
1
]
]
},
"active": {
"weight_threshold": 1,
"account_auths": [],
"key_auths": [
[
"STM5gXLneWqCr3hiUEcRUfgWBo8U4ktdbF8hLvqctqMB9ZznNNJJA",
1
]
]
},
"posting": {
"weight_threshold": 1,
"account_auths": [
[
"finally.app",
1
]
],
"key_auths": [
[
"STM8eaB64qVgR4N7do5HVZVxPPg6afRt4ZcMQ3DY989zS9f4LxrdD",
1
]
]
},
"memo": "STM5A5hoYoR9RPypz8rpCRabhnAEiRVXCFVCLCPGu6koEC4TfFLV6"
}Witness Votes
1 / 30
01.steemitboard |
[ "steemitboard" ]