Monday, August 9, 2021

Pattern introduction

Most programming languages have a concept of handling some action more than once. Loops are probably the most familiar mechanism, and most programmers are also aware of recursion. But there are other options for dealing with this need. For example, functional languages also frequently supply functions like: map, filter, flatten, fold, and others. Used creatively, many operations that seem to require a loop or recursion can be instead solved with these functions.

The benefit of map etc is that they provide well typed and composable intermediates. Loops do a bunch of stuff and then we hope that the end result makes sense. Recursion is kind of hard to glue together with other recursion. Map etc compose nicely with each other.

The problem is that there are some missing use cases where you need to fall back on recursion or loops to get the functionality that you need. If you have a tree structure and want to know about leaf nodes that have grandparent nodes in common, then you'll need some recursion. Similarly, if you have items in a collection that dictate how you iterate through the rest of the collection, then you'll need a loop.

My thought is that it should be possible to specify these things with a series of patterns. The underlying language infrastructure will need loops and recursion, but that's always the case. The programmer can focus only on the specification of the data structure that's interesting.

It seems that there's already a programming language that's trying this sort of thing. The Egison programming language. I haven't looked deeply enough into it to see if their goal is the same as my own. But a precursory glance shows some impressive results.

Wednesday, March 18, 2020

Think about it

In fiction we tend to categorize intelligence linearly. Someone is smarter than someone else and that lets them do more smart person things. Smart person things generally look like competent person things except they use words that the script writers think sound impressive. Oh and success. Being smart means being successful. All the time. First try.

In my experience intelligence isn't just non-linear, but it's down right non-transitive. You can't order people and you can't predict when someone will be competent because of their intelligence unless you've seen them do exactly the same thing before.

I'm going to explore what I think is going on.

How do we know

How do we know things? Like, if you see the number '4' written on a wall, then how do you know what it is and how do you know what it's good for?

  1. Peer Pressure
  2. Gut feeling / experience
  3. Structural analysis

Peer pressure is relying on groups of people and society's expectation in order to decide what to do. While we tell children that you shouldn't listen to peer pressure, what we actually teach them is that you should totally listen to peer pressure (just try not to listen to stupid peer pressure ... unless it's coming from arbitrary authority figure). This doesn't have to be a bad thing. For example, learning to talk comes from peer pressure.

Gut feelings and/or experience. When talking about getting out of dangerous situations, people will often talk about listening to their gut. They can't put their figure on exactly what was wrong, but they say that their gut told them something bad was going to happen. Similarly, we also talk about sufficient experience to do a specific job. If it was just about rule memorization, then anyone with a sufficiently large database on a portable device could do any job (open heart surgery, world class composer, commander of an army). We don't do things like that for a reason. We want people to have this vaguely defined 'experience'. We know it when we see it and we can't describe exactly how we did it. (Although we are good at telling stories.)

Structural analysis more or less reduces to mathematics. However, it can also be algorithms. Really anything that we trust to mechanically work out. So for example, adding very large numbers together. We might be able to use our gut reactions to know if the addition went wrong in any dramatic way. However, for the most part we're just trusting the elementry school techniques that we learned to just work. It's not all mindless though. For example, if you're adding 398 to 455, then you can structurally check the answer by saying something like, "Both numbers are lower than 500 and 500 + 500 is 1000. Additionally, both numbers are larger than 300. And 300 + 300 is 600. Therefore whatever answer we get had better be between 600 and 1000." It's a creative application of logic, but the end result can function in a mindless fashion if it has to.

I missed one way to know things. We're more or less going to skip it, but we can talk about it first to see why.

Knowing things supernaturally

My list above has a zeroth entry. Supernatural knowledge. We're going to leave this one along though because things get hopelessly unknowable pretty quickly.

God

First of all, maybe God is giving you knowledge. Some people like to theorize that maybe God is evil. But this is pretty crazy and fatalistic thinking. Like, you can't even kill yourself in the reality where God is evil. God can just bring you back. Heaven can switch to Hell at a moments notice and your entire life experience might all just be an illusion from God. People who see evil, suffering, and injustice in the world and conclude that God is evil are either suffering from a woefully inadequate imagination or they're just trying to spite God. The evil God scenario is so much worse than the evil we see in the world today. So we're going to say that God is good. If only because if God is evil then nothing else in this essay matters. The only thing that matters is the eternal suffering that we're all going to definitely go through forever.

So God is good then you're going to get good knowledge from God. Unfortunately, this does not mean that you can trust people who say that they're getting knowledge from God. For starters, someone gets knowedge from God and shares it with others. This person is going to be treated favorably by their peers. After all they're giving everyone good knowledge from God. Other people will see this and desiring to get both preferential treatment and have their personal ideas implemented by others, they will lie to others and tell them that their personal knowledge is actually God's knowledge. Just because you see someone saying that they are getting knowledge from God doesn't mean that you can trust them. Of course, there are other considerations.

Not God

Supernatural knowedge can come from God. But it can also come from supernatural sources that are not God. While we pretty much have to assume God is good if we want anything else to even matter, we don't have to assume that not God is good.

Like before we have to be concerned that a supernatural knowledge source might not actually be supernatural, but instead someone only pretending to have supernatural knowledge. But we also have to worry that someone does have supernatural knowledge which is coming from a malicious source. And then things get complicated.

What happens if a supernatural source can track what happens to the knowledge it gives before it gives it. In much the same way we're able to statically track data using sophisticated type systems, the supernatural source can ensure that it only gives out good knowledge when that knowledge only reaches the "true believers" of the supernatural source. Feel free to exhange "true believers" with any property including ones that are not computable or even down right nonsense (the supernatural source may be able to handle it using techniques not available to us in the natural world). If this is going on, then we really have no way to evaulate knowledge from a supernatural source. There's no way to for us to make sure that only "true believers" get the knowledge (and who knows why kind of criteria a supernatural source is even looking for). And besides if we have to believe in it to get it, then we can't skeptically analyize it.

But if we think about it, things can get even worse.

The ghosts are messing with us

All interviews with psychics that I have seen featured a psychic that was pretty clearly using a cold reading technique. Cold reading is a way of way of fooling people into thinking that you have special powers by saying random things that are statisically likely to be true until you land on something that is actually true. Or even just true enough. People like to agree in groups of people because peer pressure is a legitimate knowledge method. Either you're agreeing to try and leverage a good reputation for yourself or to avoid a bad reputation. Or you're agreeing because your current peer group is telling you that this is the right course of action.

Now what happens if the psychics aren't cold reading, but actually talking to ghosts. And the ghosts are the ones doing the cold reading. It would look the same as if the psychic was the one doing the cold reading. Given both possibilities we can't decide between them for sure.

You put it all together and while this can be a legitimate knowledge source, we really can't analyze it very well. There are too many places for something else to be going on.

From knowledge to thinking

The final problem with supernatural knowledge is that it's really not obvious what it means to think supernaturally. With peer pressure, experience, and structural knowledge we can extend all of them into a mode of thought, but what would supernatural thinking look like. Elisha was a prophet of God and he worked a bunch of weird miracles. He purified some soup by throwing in flour. He got an axe head to float in water by throwing in a stick after it. He cured a soldier of leprosy by having him take a bath in a river. Now maybe the bible doesn't record the part where he went off and prayed, but it looks suspiciuosly like he just said some stuff and then God followed through with a miracle. Moses was similar. Sometimes he prayed to God for what he should do, but sometimes he just said stuff and then God did stuff.

So, it looks like supernatural thought processes are a thing because Elisha and Moses were clearly doing something like it, but of intellectual analysis I think the only thing we can really say is, "what's your relationship with God look like."

Peer Pressure

Some problems are really big and in order to build up any intuition for how to deal with them you would have to live multiple lifetimes. For example, how do you encode arbitrary knowledge into a serial format that can be transmitted via accustical waves (that is how do we talk). Peer pressure allows us to construct language and it comes to surprisingly good conclusions. If you look at different knowledge domains, you see pretty much the same thing over and over. People taking complex ideas and abbreviating them with technical language. Jargon. This is actually a concept from information theory. Often used symbols need to have short representations. Pretty much every social group in the world comes up with their own jargon.

Additionally, some domains don't allow failure. Consider hunting a lion or being a soldier. If you mess up you're probably not going to live. And you can't really learn from the lesson that kills you. However, your peer group can learn from that lesson. And they can pass the information on to people who weren't even present when the fatal event occurred.

Statistics and reputation

This is a statistical method of thinking. The group notices many actions. The group comes together and talks about the actions they've noticed. Communally they decide what the right way of acting is. The process then cycles continuously. Whether or not the peer pressure results in beneficial outcomes is going to be left up to chance. A peer group with enough cycles in it will tend to give better results. And partially this is because if the peer group consistently gives bad results then it very well could die off before it gets very many cycles into the process.

Reputation also plays a role. We listen to people who have good reputations. Or at least we listen to people who seem to act like they have a good reputation. Embarrassment comes into play. If you make a statement, then follow through with action, then fail, then you will get embarrased by the group. They are less likely to listen to you next time. Also you have seen your own fallibility. You're likely to act less sure and more apt to be humble. Over time repeated success makes you look good and repeated failure makes you look bad. This causes the group to weigh your opinions higher or lower. And it causes the group to warn itself about your opinions.

Propogation speed and irrelevance

The peer group isn't going to know everything. There are going to be some low probability events that the peer group has either no frame of reference for dealing with or an incorrect frame of reference for dealing with. Different peer groups that come together and inadvertantly share knowledge (old war stories or my dad can beat up your dad stories) will sometimes transfer knowledge about low probability events. And sometimes the transfer will fail. But all of this takes time. The peer group can only transfer knowledge at the speed of failure plus communication. And only when the information is actually accepted.

Of course the peer group will only work while the context that makes it effective is true. Things change sometimes. If the change is slow enough, the new context is comprised of low probability events, and if failure is non-lethal enough, then the peer group might survive and change to match the new context. Or it will die off or become irrelevant.

Why and why not

Peer pressure can work really well for solving difficult problems. It can also solve problems that don't have any necessary component in the solution. For example, there are many different languages in the world that all work very well for conveying information. Additionally, there are many different ways of greeting people such that they do not view you as a dangerous threat. It's all different and there's no way that any of it had to be. We just needed some method.

Peer pressure takes a while to converge into a stable enough pattern that it can be relied upon. And it doesn't react very well to significant change. The knowledge is also distributed. Which helps it survive, but also means that understanding the whole picture can end up impossible.

Probably the biggest problem is that peer pressure recognizes appearance over actuality. An individual who learns how to appear like someone with a good reputation may be accepted as someone with a good reputation. An individual who is willing to lie about good and bad actions has to be listened to or rejected by the group. The group can make a mistake. And the group may also decide to ignore good information by someone who does not know the right way to present themselves or their idea.

Experience

Peer pressure is a statistical method that is distributed across many people. Then experience is a statistical method that is centered on one person.

Much like peer pressure, your experience relies on your failures. Peer pressure relies on some sort of social introspective to collectively occur and that can take a lot of time as can the cycle between experimentation and introspection. Experience can benefit from an introspective phase, but you can also introspect subconsciously. And cycling between failure and introspection can happen very quickly.

While peer groups can be influenced negatively because of the messenger's social abilities (either accepting bad messengers because of good social skills or ignoring good messengers because of bad social skills), your experience can instead look at raw evidence. Of course you can always lie to yourself or have hidden biases, but at least you have direct access to your experiences.

Still statistics

Your experience is still a statistical method just like peer pressure. This means that there are going to be cases where your experience tells you that something is right when that thing is actually wrong. Again, more cycles where you think that you know the solution to a problem, attempt to solve the problem, and then success or failure, will tend to produce better results.

However, too many cycles can also cause problems if your experience gets overfit for a specific scenario. You might become hypercompetent at the scenario, however it can be difficult to accept that your experience is not valid for other scenarios that do not share enough aspects of the one which you are overfit for.

Stories

Because experience is just a statistic method that your brain runs, it can be very difficult to convey to other people why or how you know the correct answer. Or even convey why something is a correct answer. The most extreme examples are when people report getting "a bad feeling in their gut" about a scenario. They admit that they don't know why they needed to get to safety, but they knew that it was necessary.

As a result, if you want to share your experience with a peer group, then you'll need to be good at telling a story about your experience. This could mean that you are literally a good story teller or it might just mean that you know how to make the story acceptable to the peer group. The story itself functions as security of reputation to the person who accepts it.

If someone accepts your experience but then fails when attempting to apply it, they will need to find a way to protect their reputation in front of their peer group. If they don't have a good story, then they could easily lose their reputation when their peer group is not satisified. Making bad decisions without good insurance might indicate other flaws, better to be safe and ignore you in the future. However, if you have a compelling story, then the blame can be shifted to chance and happenstance.

Why and why not

Experience is going to work best when you're in a scenario where you can maintain a quick cycle between introspection and experimentation. Additionally, failure needs to be cheap and not fatal. In these scenarios you can quickly build up experience for very complex problems that a peer group would fail to be able to solve on its own.

In order for this to work effectively, you need good instincts for the problem. Or at the least be able to build up good instincts quickly. Repeated failure may eventually cost too much or end up with reputation damage.

Additionally, if the scenario has failures that look like success but are actually slow failures, then experience will tend to send you in a direction that only makes you successful in the short term. In the long term things will collapse. Experience will probably not help you break out of that cycle. For that you need to be able to recognize a causal connection between events. For that you need some sort of structural thinking.

Structural

Mathematics is kind of weird. You pick a set of axioms and a set of inference rules and then you try to see what's possible in that space. Some things are believed to be false or true and others are proved to be false or true. It isn't always possible to map back to reality.

I like the term 'structural' more than I like the term 'mathematical' because this mode of thinking can sometimes have a tenuous relation to mathematics. Algorithms like long division or what you put into a computer can modeled mathematically, but sometimes the formal mathematical modeling is overly complex and a naive approach can be more than sufficient. Sometimes just being aware that causality is a thing (that is things cause other things to happen) can be enough to get structural knowledge or do structural thinking.

Not really statistics

The best thing about structural thinking is that it escapes the statistical trap that peer pressure and experience can both fall into. You have axioms and you have inference rules (in some form or another) and all you have to do is map them to your problem and you can get correct answers. This process is also often very easy to encode into a computer (at least compared to peer pressure and experience).

There are still avenues for failure though. Mathematical mistakes happen and bad assumptions about the applicability of a structure to a real life scenario can occur. However, regardless if you have a success or a failure, the structural mode carries along with it an explanation for how you arrived at your destination.

Real explanations

A structural solution is going leave behind a trail that can be examined later. If things are more mathematical in nature, then this trail will look like a formal proof. If they are less mathematical, then it might look like a sequence of justifications, a series of differences, or a path that was traveled.

Regardless, the trail can be checked. Either it can be checked to try to understand why it worked correctly or it can be checked to find where the flaw was that caused it to fail.

Why and why not

Escaping statistics and providing clues as to why a specific structural thought works or fails is the most compelling aspect of structural thinking. As long as you're matching up the structure to reality correctly, then you should always succeed.

The downside though is that sometimes the structure you have doesn't fit the scenario you find yourself in. Additionally, building new structures can sometimes take a very long time. There are some theorems in mathematics that have taken hundreds of years to solve.

Additionally, figuring out how to get a peer group to accept a structure can be very difficult. Just because there's a trail that shows why something works, doesn't mean that there is a story that is acceptable to the group. And if the structural approach is exotic or different enough from the status quo, then it may be very hard to find any allies that have experience with your approach.

Some here some there

Everyone does all of these. At the very least to some extent. To learn how to talk, you have to be able to act on the peer pressure of those teaching you the language (at least for your first language). To learn how to walk, you have to build up experience from repeated failures. And to have any sort of ability to navigate failures with causes that have any sort of significant delay in their manifestation, then you have to be able to create some type of structural connections.

Having capability doesn't imply competence or favorability. I think that each individual is going to favor different thinking modes for different aspects of their lives. Some might specialize in a single thought mode across the board, while others might mix and match depending on the situation.

I've found that for myself I tend to use peer pressure for dealing with shallow social interactions and structural thinking for dealing with deeper social interactions or social interactions that might lead to action or commitments on my part. For problem solving, I prefer to use structural thinking. My experience type of thinking for problem solving tends to lead me to incorrect answers if I don't already have a structural framework for the problem in place. This makes a lot of problem solving frustrating for me until I'm able to figure out a structure, but it also accelerates finding that structure because I'm good at finding the edge cases and inconsistencies. On the other hand I am able to form good intuition around problems involving physical motion or kinematics.

Friday, April 26, 2019

Problem Calculus: Spaces

  • Semantically Homogeneous:  A space where each dimension can be combined into a larger uniform multidimensional space.  Movement in each dimension is effectively the same as movement in any other dimension.  Only differing by a rotation.  For example, a function that has the signature "int * int * int -> unit" where we are representing a point in 3D euclidean space.  Each parameter is a different axis (x,y,z) in the coordinate plane.
  • Semantically Heterogeneous:  A space where each dimension cannot be combined into a larger uniform space because each dimension serves a radically different purpose.  For example, if you had the function signature from before "int * int * int -> unit", but this time if the first "int" represented "age", the second one represented "width", and the last one represented "RGB color".  In this instance the different dimensions of the space aren't uniform and each have different meaning.  You can still plot a 3D point in this space, but the meaning of moving in one dimension is radically different than the meaning of moving in another dimension.  
  • Indexed Dimension:  Where the value of one of the dimensions modifies the semantics of another of the dimensions.  For example, the type "bool * int * int" may have the meaning:  "true * x * y" and "false * r * θ".  When the boolean is true, then the space indicates a typical coordinate plane.  But when the boolean is false, then the space indicates a polar coordinate plane.  
  • Indirectly Related Dimension:  Typically, a space will have dimensions where each one is free to associate and relate to any other without any effort required.  For example, if you have "x,y,z" then you are free to consider "x + y" or "x + z" or "y + z".  Each one can reach each other space directly.  However, if your space instead looks like "linked_list<int; 3>" then the first dimension reaches the second one directly.  And the second dimension reaches the third one.  In general it makes sense to start thinking about all dimensions that are related by some predicate.  For example, all even dimensions or all dimensions separated by 18 other dimensions.  
    • Omni Related:  Typical dimensional relationships.  Everything can access everything else and it doesn't make sense to pair off the dimensions.
    • List Related:  Like the linked_list example above.  The dimensions are related to each other like on a number line.
    • Tree Related:  If you're building a tree, then the relationships can get more complicated yet.  Perhaps you want all dimensions that belong in a certain sub tree.  Or worse yet perhaps you care about dimensions that are siblings or cousins with some specific path or families of paths between them.
    • Graph Related:  Worse case scenario is that your dimensions have arbitrary relationships to other dimensions, but not omni related (or maybe sometimes they are omni related ... you have to check each time).
    • Other?:  There are generalizations of graphs, but I'm not sure things fundamentally change.  A hypergraph can be represented by a specialized graph and the relationships between dimensions are going to be preserved.
  • Abstraction Confusion:  If you have a graph (also applies to lists and trees) and the contained objects in each node have the possibility to reference the containing graph nodes.
  • Isolation Confusion:  If you have a graph (also applies to lists and trees) and the contained objects in each node have the possibility to reference contained objects in other nodes of the graph.

Friday, February 1, 2019

Problem Calculus: Index




Problem Calculus: Paths and Non-Overlapping Arrow Spaces

In addition to everything we've covered so far, you can also encounter families of spaces that have properties that make it complex.

The first thing to consider is when you have more than one path that gets you to the same destination space when starting from a given source space.


In the diagram above, we're starting with a starting element called "A".  Two arrows can take A and go to one space or another.  Finally, they arrive at a final space.  The question is:  Are the final elements equal to each other.  Ideally, you want the final two elements to be equal.  This property allows you to worry less about the spaces you're going to and the spaces you're coming from.  If this holds for all elements in the space, then you can consider the multiple paths as if they were the same and it is easier to form an intuition about the system.

Additionally, you have to be concerned about arrow spaces (input and output) that are non-overlapping in any given main space.  The issue is that it becomes difficult to know when the output of one arrow can be used for the input of another arrow.  Additionally, when trying to decide what paths exist in your system, you have to be concerned about whether the non-overlapping arrow spaces allow a path to exist.  And some paths will only sometimes exist if the arrow spaces are only partially overlapping.

Here are two arrow spaces where the incoming arrows form partial overlapping spaces.


Here are two arrow spaces where the outgoing arrows form partial overlapping spaces.


Finally, here is an incoming arrow forming a partial overlapping space with an outgoing arrow space.


All of those spaces are arrow input or output spaces that live inside of a source/destination space.  The outer space is being left out in the previous examples.

Consider the following diagram.


This diagram shows two possible paths that go through the featured space.  In one instance the arrows form partial overlapping arrow spaces.  This path will only sometimes work because some elements in the output space will be outside of the input space for the next arrow.  Additionally, one of the output spaces is completely non-overlapping with the input space of the exiting arrow.  Even though the arrow looks like it should produce values that can be used for the exiting arrow when you make a further analysis you'll discover that the elements will never be usable.

Wednesday, January 30, 2019

Problem Calculus: Arrow Complexity

With complexity projection we saw how an arrow could be difficult to comprehend because of the complexity of the spaces that it is related to.  However, arrows can also be hard to comprehend (or at the very least increase the complexity of the system as a whole) because of qualities that they have which have little to do with the spaces they are involved with.

The first type of arrow that is difficult to comprehend is the discontinuous arrow.


A discontinuous arrow is problematic because small changes in the input of the arrow will result in large (or unpredictable) changes in the output.  This will hinder building an intuition with how the arrow works.  This can be highly problematic because it means that the mostly likely way people will use it will be to just kind of try things until they get the right output.  This is mostly fine as long as two things are true 1) the input remains static so it doesn't change once the 'correct' value is picked and 2) the value never needs to be changed without allowing for sufficient analysis to ensure that the output will be okay.  

Discontinuous arrows are also problematic if the destination space is complex.  For example, a destination space with many invalid elements will not pair well with a discontinuous arrow because it will be very difficult to determine when a small change will knock your output value into an invalid value.

Next, non-deterministic arrows.


Non-deterministic arrows are difficult to comprehend because a single input element will produce different output elements at different invocations of the arrow.  This is problematic because you have to handle all possible output elements, but if you're not paying close enough attention you might not notice that different possibilities are even something that can occur.

And finally there are non-injective arrows.


An injective arrow would be one that every input element uniquely maps to a corresponding output element.  Non-injective arrows have more than one input element that can map to a given output element.  This is problematic when you are unaware or forget that you are dealing with a non-injective arrow.  Seeing a given output it is easy to make a bad assumption and believe that you know what the input element was.  The assumption will even sometimes be correct, which will further hinder a correct understanding of the system.

Problem Calculus: Complexity Projection

Early on in my investigation into cognitive complexity, I noticed that you couldn't necessarily separate the difficulty of understanding a concept from the other concepts that interact with it in the system that you are concerned with.  This was a bit surprising because before that I had done a bunch of work with type theory, lambda calculus, and functional programming.  In all of these fields being able to compose functions such that the internals are hidden is a major and recurring concept.

I didn't immediately realize that it should be part of my development of problem calculus, but I set it apart to be examined later.  However, eventually I realized that separating concepts into different modules, objects, or functions (to take a programming perspective) doesn't necessarily make a concept easier to deal with.  Sometimes the complexity of a concept leaks.  I noticed that my previous idea already stated this exact concept.  And thus Complexity Projection was born.


We've already encountered arrows in the previous problem calculus diagrams, however this arrow doesn't indicate a transform from one space to another.  This arrow indicates the complexity from one space leaking into another space.

Currently, my assertion is that complexity leaks in the following manner.


The destination space will leak complexity into the output space for any given arrow.  The output space will leak complexity into the input space of the related arrow.  The input space will leak complexity into the source space.  And finally the source space will leak complexity into any arrows that map it to other spaces.

Leaking complexity basically means that if one thing is difficult to deal with cognitively, then anything that the concept leaks complexity into will also be similarly difficult to deal with cognitively even if it is otherwise simple.  The term I've been using for this leakage is complexity projection.

For justification about the direction of the projection, consider the previous blog post about invalid elements.  If you have an output space with no invalid elements, but the destination space has many invalid elements, then the output space is going be harder to handle because it will admit elements that do not work with the space it is a subspace of.  For a contrived example imagine the function "f(x) = x + 1".  The output of this function is any number.  Now imagine that the destination space is the set of all odd numbers.  Because the destination space only lets you have odd numbers, the function output space is harder to deal with because you have to make sure that you do not clash with the requirements of the destination space even though it is not a requirement for the output space.

Similarly, the output space projects complexity onto the input space because a set of valid inputs will need to walk on eggshells to avoid failure from the set of invalid outputs.  The same principle again arises when projecting complexity from the input space to the source space.  And finally any arrow that goes from one space to the other will have all the complexity from the entire system projected onto it.  Or in other words, arrows between two spaces are hard to use because the spaces themselves are hard to comprehend.

As an example of this principle consider compilers.  A compiler is an arrow that transfers an element from the space of strings (ie source code) to the space of binary executables.  The space of strings is actually really simple.  It's the set of all possible character combinations.  However, the input space is already highly constrained.  It has many invalid elements (ex invalid parsing tokens) and the space itself is highly semantically heterogeneous.  There are many different concepts that all get mashed together in the source code.  The input space projects its complexity onto the source space.  Similarly, the output space also has many invalid elements (ex ill typed programs).  This also projects complexity.  Finally, the whole system projects onto the arrow (ie the complier).  So we shouldn't be surprised that compilers are hard for beginners to get used to even though the input (just a bunch of words and brackets) doesn't seem to be innately complicated.