问:
Right way to parse chain of various binary functions with `Parsec`?
It is true that Parsec has chainl and chainr to parse chains of either left-associative or right-associative operations (i.e. a -> a -> a). So I could quite easily parse something like x + y + z in a ((a + y) + z) or (a + (y + z)) manner.

However,

there is no standard way to parse a -> b -> c functions and specific case when a = b: a -> a -> c, for example a = b = c thought as a comparison function (a -> a -> Bool);

there is no standard way to implement "importance" of an operation: for example a + b = b + a should be parsed as ((a + b) = (b + a)) and not (((a + b) = b) + a)).

I am kind of new to parsing problems, so it would be great to get answers for both questions.

答:
Okay, here's a long answer that might help. First, these are the imports I'm using, if you want to follow along:

```<code>{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wall #-}
import Control.Applicative (some)
import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.String
</code>```

Why a -> a -> a isn't so bad...

The operator type signature a -> a -> a is less restrictive and makes more sense than you might at first think.  One key point is that usually when we're parsing expressions, we don't write a parser to evaluate them directly but rather parse them into some intermediate abstract syntax tree (AST) that is later evaluated.  For example, consider a simple untyped AST with addition, subtraction, equality, and boolean connectives:

```<code>data Expr
  = IntE Int        -- integer literals
  | FalseE | TrueE  -- boolean literals (F, T)
  | AddE Expr Expr  -- x + y
  | SubE Expr Expr  -- x - y
  | EqE  Expr Expr  -- x = y
  | OrE  Expr Expr  -- x | y
  | AndE Expr Expr  -- x & y
  deriving (Show)
</code>```

If we want to write a parser to treat all these operators as left associative at the same precedence level, we can write a chainl-based parser like so.  (For simplicity, this parser doesn't permit whitespace.)

```<code>expr :: Parser Expr
expr = chainl1 term op
  where op = AddE <$ char '+'
         <|> SubE <$ char '-'
         <|> EqE  <$ char '='
         <|> OrE  <$ char '|'
         <|> AndE <$ char '&'
term :: Parser Expr
term = IntE . read <$> some digit
   <|> FalseE <$ char 'F' <|> TrueE <$ char 'T'
   <|> parens expr
parens :: Parser a -> Parser a
parens = between (char '(') (char ')')
</code>```

and we get:

```<code>> parseTest expr "1+2+3"
AddE (AddE (IntE 1) (IntE 2)) (IntE 3)
> parseTest expr "1=2=F"
EqE (EqE (IntE 1) (IntE 2)) FalseE
>
</code>```

We'd then leave it up to the interpreter to deal with the types (i.e., to type check the program):

```<code>data Value = BoolV Bool | IntV Int deriving (Eq, Show)
eval :: Expr -> Value
eval (IntE x) = IntV x
eval FalseE = BoolV False
eval TrueE = BoolV True
eval (AddE e1 e2)
  = let IntV v1 = eval e1  -- pattern match ensures right type
        IntV v2 = eval e2
    in  IntV (v1 + v2)
eval (SubE e1 e2)
  = let IntV v1 = eval e1
        IntV v2 = eval e2
    in  IntV (v1 - v2)
eval (EqE e1 e2) = BoolV (eval e1 == eval e2)  -- equal if same type and value
eval (OrE e1 e2)
  = let BoolV v1 = eval e1
        BoolV v2 = eval e2
    in  BoolV (v1 || v2)
eval (AndE e1 e2)
  = let BoolV v1 = eval e1
        BoolV v2 = eval e2
    in  BoolV (v1 && v2)

evalExpr :: String -> Value
evalExpr str = let Right e = parse expr "<evalExpr>" str in eval e
</code>```

giving:

```<code>> evalExpr "1+2+3"
IntV 6
> evalExpr "1=2=F"
BoolV True
>
</code>```

Note that even though the type of the "=" operator is something like Eq a => a -> a -> Bool (or actually a -> b -> Bool, as we allow comparison of unequal types), it's represented in the AST as the constructor EqE of type Expr -> Expr -> Expr, so the a -> a -> a type makes sense.

Even if we were to combine the parser and evaluator above into a single function, we'd probably find it easiest to use a dynamic Value type, so all operators would be of type Value -> Value -> Value which fits into the a -> a -> a pattern:

```<code>expr' :: Parser Value
expr' = chainl1 term' op
  where op = add <$ char '+'
         <|> sub <$ char '-'
         <|> eq  <$ char '='
         <|> or  <$ char '|'
         <|> and <$ char '&'
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
        eq  v1 v2 = BoolV $ v1 == v2
        or  (BoolV x) (BoolV y) = BoolV $ x || y
        and (BoolV x) (BoolV y) = BoolV $ x && y
term' :: Parser Value
term' = IntV . read <$> some digit
   <|> BoolV False <$ char 'F' <|> BoolV True <$ char 'T'
   <|> parens expr'
</code>```

This works too, with the parser directly evaluating the expression

```<code>> parseTest expr' "1+2+3"
IntV 6
> parseTest expr' "1=2=F"
BoolV True
>
</code>```

You may find this use of dynamic typing during parsing and evaluation a little unsatifactory, but see below.

Operator Precedence

The standard way of adding operator precedence is to define multiple expression "levels" that work with a subset of the operators.  If we want a precedence ordering from highest to lowest of addition/subtraction, then equality, then boolean "and", then boolean "or", we could replace expr' with the following.  Note that each chainl1 call uses as "terms" the next (higher-precedence) expression level:

```<code>expr0 :: Parser Value
expr0 = chainl1 expr1 op
  where op = or  <$ char '|'
        or  (BoolV x) (BoolV y) = BoolV $ x || y
expr1 :: Parser Value
expr1 = chainl1 expr2 op
  where op = and <$ char '&'
        and (BoolV x) (BoolV y) = BoolV $ x && y
expr2 :: Parser Value
expr2 = chainl1 expr3 op
  where op = eq  <$ char '='
        eq  v1 v2 = BoolV $ v1 == v2
expr3 :: Parser Value
expr3 = chainl1 term'' op
  where op = add <$ char '+'  -- two operators at same precedence
         <|> sub <$ char '-'
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
term'' :: Parser Value
term'' = IntV . read <$> some digit
     <|> BoolV False <$ char 'F' <|> BoolV True <$ char 'T'
     <|> parens expr0
</code>```

After which:

```<code>> parseTest expr0 "(1+5-6=2-3+1&2+2=4)=(T|F)"
BoolV True
>
</code>```

As this can be tedious, Parsec provides a Text.Parsec.Expr that makes this easier.  The following replaces expr0 through expr3 above:

```<code>expr0' :: Parser Value
expr0' = buildExpressionParser table term''
  where table = [ [binary '+' add, binary '-' sub]
                , [binary '=' eq]
                , [binary '&' and]
                , [binary '|' or]
                ]
        binary c op = Infix (op <$ char c) AssocLeft
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
        eq  v1 v2 = BoolV $ v1 == v2
        and (BoolV x) (BoolV y) = BoolV $ x && y
        or  (BoolV x) (BoolV y) = BoolV $ x || y
</code>```

Typed Parsing

You may find it strange above that we use an untyped AST (i.e., everything's an Expr) and dynamically typed Value instead of using Haskell's type system in the parsing.  It is possible to design a parser where the operators actually have expected Haskell types.  In the language above, equality causes a bit of an issue, but if we permit integer equality only, it's possible to write a typed parser/evaluator as follows.  Here bexpr and iexpr are for boolean-valued and integer-values expressions respectively.

```<code>bexpr0 :: Parser Bool
bexpr0 = chainl1 bexpr1 op
  where op = (||) <$ char '|'
bexpr1 :: Parser Bool
bexpr1 = chainl1 bexpr2 op
  where op = (&&) <$ char '&'
bexpr2 :: Parser Bool
bexpr2 = False <$ char 'F' <|> True <$ char 'T'
     <|> try eqexpr
     <|> parens bexpr0
     where eqexpr = (==) <$> iexpr3 <* char '=' <*> iexpr3  -- this can't chain now
iexpr3 :: Parser Int
iexpr3 = chainl1 iterm op
  where op = (+) <$ char '+'
         <|> (-) <$ char '-'
iterm :: Parser Int
iterm = read <$> some digit
     <|> parens iexpr3
</code>```

Note that we're still able to use chainl1, but there's a boundary between the integer and boolean types enforced by precedence, so we only ever chain Int -> Int -> Int or Bool -> Bool -> Bool operators, and we don't let the Int -> Int -> Bool integer equality operator chain.

This also means we need to use a different parser to parse a boolean versus an integer expression:

```<code>> parseTest bexpr0 "1+2=3"
True
> parseTest iexpr3 "1+2-3"  -- iexpr3 is top-most integer expression parser
0
>
</code>```

Note here that if you wanted integer equality to chain as a set of equalities so that 1+1=2=3-1 would check that all three terms are equal, you could do this with chainl1 using some trickery with lists and singleton values, but it's easier to use sepBy1 and replace eqexpr above with the definition:

```<code>eqexpr' = do
  x:xs <- sepBy1 iexpr3 (char '=')
  return $ all (==x) xs
</code>```

giving:

```<code>> parseTest bexpr0 "1+1=2=3-1"
True

</code>```

The whole program

To summarize, here's all the code:

```<code>{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wall #-}

import Control.Applicative (some)
import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.String

-- * Untyped parser to AST

data Expr
  = IntE Int        -- integer literals
  | FalseE | TrueE  -- boolean literals (F, T)
  | AddE Expr Expr  -- x + y
  | SubE Expr Expr  -- x - y
  | EqE  Expr Expr  -- x = y
  | OrE  Expr Expr  -- x | y
  | AndE Expr Expr  -- x & y
  deriving (Show)

expr :: Parser Expr
expr = chainl1 term op
  where op = AddE <$ char '+'
         <|> SubE <$ char '-'
         <|> EqE  <$ char '='
         <|> OrE  <$ char '|'
         <|> AndE <$ char '&'

term :: Parser Expr
term = IntE . read <$> some digit
   <|> FalseE <$ char 'F' <|> TrueE <$ char 'T'
   <|> parens expr

parens :: Parser a -> Parser a
parens = between (char '(') (char ')')

-- * Interpreter

data Value = BoolV Bool | IntV Int deriving (Eq, Show)

eval :: Expr -> Value
eval (IntE x) = IntV x
eval FalseE = BoolV False
eval TrueE = BoolV True
eval (AddE e1 e2)
  = let IntV v1 = eval e1  -- pattern match ensures right type
        IntV v2 = eval e2
    in  IntV (v1 + v2)
eval (SubE e1 e2)
  = let IntV v1 = eval e1
        IntV v2 = eval e2
    in  IntV (v1 - v2)
eval (EqE e1 e2) = BoolV (eval e1 == eval e2)  -- equal if same type and value
eval (OrE e1 e2)
  = let BoolV v1 = eval e1
        BoolV v2 = eval e2
    in  BoolV (v1 || v2)
eval (AndE e1 e2)
  = let BoolV v1 = eval e1
        BoolV v2 = eval e2
    in  BoolV (v1 && v2)

-- * Combined parser/interpreter with no intermediate AST

expr' :: Parser Value
expr' = chainl1 term' op
  where op = add <$ char '+'
         <|> sub <$ char '-'
         <|> eq  <$ char '='
         <|> or  <$ char '|'
         <|> and <$ char '&'
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
        eq  v1 v2 = BoolV $ v1 == v2
        or  (BoolV x) (BoolV y) = BoolV $ x || y
        and (BoolV x) (BoolV y) = BoolV $ x && y
term' :: Parser Value
term' = IntV . read <$> some digit
   <|> BoolV False <$ char 'F' <|> BoolV True <$ char 'T'
   <|> parens expr'

-- * Parser/interpreter with operator precendence

expr0 :: Parser Value
expr0 = chainl1 expr1 op
  where op = or  <$ char '|'
        or  (BoolV x) (BoolV y) = BoolV $ x || y
expr1 :: Parser Value
expr1 = chainl1 expr2 op
  where op = and <$ char '&'
        and (BoolV x) (BoolV y) = BoolV $ x && y
expr2 :: Parser Value
expr2 = chainl1 expr3 op
  where op = eq  <$ char '='
        eq  v1 v2 = BoolV $ v1 == v2
expr3 :: Parser Value
expr3 = chainl1 term'' op
  where op = add <$ char '+'  -- two operators at same precedence
         <|> sub <$ char '-'
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
term'' :: Parser Value
term'' = IntV . read <$> some digit
     <|> BoolV False <$ char 'F' <|> BoolV True <$ char 'T'
     <|> parens expr0

-- * Alternate implementation using buildExpressionParser

expr0' :: Parser Value
expr0' = buildExpressionParser table term''
  where table = [ [binary '+' add, binary '-' sub]
                , [binary '=' eq]
                , [binary '&' and]
                , [binary '|' or]
                ]
        binary c op = Infix (op <$ char c) AssocLeft
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
        eq  v1 v2 = BoolV $ v1 == v2
        and (BoolV x) (BoolV y) = BoolV $ x && y
        or  (BoolV x) (BoolV y) = BoolV $ x || y

-- * Typed parser/interpreter with separate boolean and integer expressions

bexpr0 :: Parser Bool
bexpr0 = chainl1 bexpr1 op
  where op = (||) <$ char '|'
bexpr1 :: Parser Bool
bexpr1 = chainl1 bexpr2 op
  where op = (&&) <$ char '&'
bexpr2 :: Parser Bool
bexpr2 = False <$ char 'F' <|> True <$ char 'T'
     <|> try eqexpr
     <|> parens bexpr0
     where eqexpr = (==) <$> iexpr3 <* char '=' <*> iexpr3  -- this can't chain now
iexpr3 :: Parser Int
iexpr3 = chainl1 iterm op
  where op = (+) <$ char '+'
         <|> (-) <$ char '-'
iterm :: Parser Int
iterm = read <$> some digit
     <|> parens iexpr3

-- * Alternate definition of eqexpr to allow 4=2+2=1+3

eqexpr' = do
  x:xs <- sepBy1 iexpr3 (char '=')
  return $ all (==x) xs
</code>```

Body:
Okay, here's a long answer that might help. First, these are the imports I'm using, if you want to follow along:

{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wall #-}
import Control.Applicative (some)
import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.String

Why a -> a -> a isn't so bad...

The operator type signature a -> a -> a is less restrictive and makes more sense than you might at first think.  One key point is that usually when we're parsing expressions, we don't write a parser to evaluate them directly but rather parse them into some intermediate abstract syntax tree (AST) that is later evaluated.  For example, consider a simple untyped AST with addition, subtraction, equality, and boolean connectives:

data Expr
  = IntE Int        -- integer literals
  | FalseE | TrueE  -- boolean literals (F, T)
  | AddE Expr Expr  -- x + y
  | SubE Expr Expr  -- x - y
  | EqE  Expr Expr  -- x = y
  | OrE  Expr Expr  -- x | y
  | AndE Expr Expr  -- x & y
  deriving (Show)

If we want to write a parser to treat all these operators as left associative at the same precedence level, we can write a chainl-based parser like so.  (For simplicity, this parser doesn't permit whitespace.)

expr :: Parser Expr
expr = chainl1 term op
  where op = AddE <$ char '+'
         <|> SubE <$ char '-'
         <|> EqE  <$ char '='
         <|> OrE  <$ char '|'
         <|> AndE <$ char '&'
term :: Parser Expr
term = IntE . read <$> some digit
   <|> FalseE <$ char 'F' <|> TrueE <$ char 'T'
   <|> parens expr
parens :: Parser a -> Parser a
parens = between (char '(') (char ')')

and we get:

> parseTest expr "1+2+3"
AddE (AddE (IntE 1) (IntE 2)) (IntE 3)
> parseTest expr "1=2=F"
EqE (EqE (IntE 1) (IntE 2)) FalseE
>

We'd then leave it up to the interpreter to deal with the types (i.e., to type check the program):

data Value = BoolV Bool | IntV Int deriving (Eq, Show)
eval :: Expr -> Value
eval (IntE x) = IntV x
eval FalseE = BoolV False
eval TrueE = BoolV True
eval (AddE e1 e2)
  = let IntV v1 = eval e1  -- pattern match ensures right type
        IntV v2 = eval e2
    in  IntV (v1 + v2)
eval (SubE e1 e2)
  = let IntV v1 = eval e1
        IntV v2 = eval e2
    in  IntV (v1 - v2)
eval (EqE e1 e2) = BoolV (eval e1 == eval e2)  -- equal if same type and value
eval (OrE e1 e2)
  = let BoolV v1 = eval e1
        BoolV v2 = eval e2
    in  BoolV (v1 || v2)
eval (AndE e1 e2)
  = let BoolV v1 = eval e1
        BoolV v2 = eval e2
    in  BoolV (v1 && v2)

evalExpr :: String -> Value
evalExpr str = let Right e = parse expr "<evalExpr>" str in eval e

giving:

> evalExpr "1+2+3"
IntV 6
> evalExpr "1=2=F"
BoolV True
>

Note that even though the type of the "=" operator is something like Eq a => a -> a -> Bool (or actually a -> b -> Bool, as we allow comparison of unequal types), it's represented in the AST as the constructor EqE of type Expr -> Expr -> Expr, so the a -> a -> a type makes sense.

Even if we were to combine the parser and evaluator above into a single function, we'd probably find it easiest to use a dynamic Value type, so all operators would be of type Value -> Value -> Value which fits into the a -> a -> a pattern:

expr' :: Parser Value
expr' = chainl1 term' op
  where op = add <$ char '+'
         <|> sub <$ char '-'
         <|> eq  <$ char '='
         <|> or  <$ char '|'
         <|> and <$ char '&'
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
        eq  v1 v2 = BoolV $ v1 == v2
        or  (BoolV x) (BoolV y) = BoolV $ x || y
        and (BoolV x) (BoolV y) = BoolV $ x && y
term' :: Parser Value
term' = IntV . read <$> some digit
   <|> BoolV False <$ char 'F' <|> BoolV True <$ char 'T'
   <|> parens expr'

This works too, with the parser directly evaluating the expression

> parseTest expr' "1+2+3"
IntV 6
> parseTest expr' "1=2=F"
BoolV True
>

You may find this use of dynamic typing during parsing and evaluation a little unsatifactory, but see below.

Operator Precedence

The standard way of adding operator precedence is to define multiple expression "levels" that work with a subset of the operators.  If we want a precedence ordering from highest to lowest of addition/subtraction, then equality, then boolean "and", then boolean "or", we could replace expr' with the following.  Note that each chainl1 call uses as "terms" the next (higher-precedence) expression level:

expr0 :: Parser Value
expr0 = chainl1 expr1 op
  where op = or  <$ char '|'
        or  (BoolV x) (BoolV y) = BoolV $ x || y
expr1 :: Parser Value
expr1 = chainl1 expr2 op
  where op = and <$ char '&'
        and (BoolV x) (BoolV y) = BoolV $ x && y
expr2 :: Parser Value
expr2 = chainl1 expr3 op
  where op = eq  <$ char '='
        eq  v1 v2 = BoolV $ v1 == v2
expr3 :: Parser Value
expr3 = chainl1 term'' op
  where op = add <$ char '+'  -- two operators at same precedence
         <|> sub <$ char '-'
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
term'' :: Parser Value
term'' = IntV . read <$> some digit
     <|> BoolV False <$ char 'F' <|> BoolV True <$ char 'T'
     <|> parens expr0

After which:

> parseTest expr0 "(1+5-6=2-3+1&2+2=4)=(T|F)"
BoolV True
>

As this can be tedious, Parsec provides a Text.Parsec.Expr that makes this easier.  The following replaces expr0 through expr3 above:

expr0' :: Parser Value
expr0' = buildExpressionParser table term''
  where table = [ [binary '+' add, binary '-' sub]
                , [binary '=' eq]
                , [binary '&' and]
                , [binary '|' or]
                ]
        binary c op = Infix (op <$ char c) AssocLeft
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
        eq  v1 v2 = BoolV $ v1 == v2
        and (BoolV x) (BoolV y) = BoolV $ x && y
        or  (BoolV x) (BoolV y) = BoolV $ x || y

Typed Parsing

You may find it strange above that we use an untyped AST (i.e., everything's an Expr) and dynamically typed Value instead of using Haskell's type system in the parsing.  It is possible to design a parser where the operators actually have expected Haskell types.  In the language above, equality causes a bit of an issue, but if we permit integer equality only, it's possible to write a typed parser/evaluator as follows.  Here bexpr and iexpr are for boolean-valued and integer-values expressions respectively.

bexpr0 :: Parser Bool
bexpr0 = chainl1 bexpr1 op
  where op = (||) <$ char '|'
bexpr1 :: Parser Bool
bexpr1 = chainl1 bexpr2 op
  where op = (&&) <$ char '&'
bexpr2 :: Parser Bool
bexpr2 = False <$ char 'F' <|> True <$ char 'T'
     <|> try eqexpr
     <|> parens bexpr0
     where eqexpr = (==) <$> iexpr3 <* char '=' <*> iexpr3  -- this can't chain now
iexpr3 :: Parser Int
iexpr3 = chainl1 iterm op
  where op = (+) <$ char '+'
         <|> (-) <$ char '-'
iterm :: Parser Int
iterm = read <$> some digit
     <|> parens iexpr3

Note that we're still able to use chainl1, but there's a boundary between the integer and boolean types enforced by precedence, so we only ever chain Int -> Int -> Int or Bool -> Bool -> Bool operators, and we don't let the Int -> Int -> Bool integer equality operator chain.

This also means we need to use a different parser to parse a boolean versus an integer expression:

> parseTest bexpr0 "1+2=3"
True
> parseTest iexpr3 "1+2-3"  -- iexpr3 is top-most integer expression parser
0
>

Note here that if you wanted integer equality to chain as a set of equalities so that 1+1=2=3-1 would check that all three terms are equal, you could do this with chainl1 using some trickery with lists and singleton values, but it's easier to use sepBy1 and replace eqexpr above with the definition:

eqexpr' = do
  x:xs <- sepBy1 iexpr3 (char '=')
  return $ all (==x) xs

giving:

> parseTest bexpr0 "1+1=2=3-1"
True

The whole program

To summarize, here's all the code:

{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wall #-}

import Control.Applicative (some)
import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.String

-- * Untyped parser to AST

data Expr
  = IntE Int        -- integer literals
  | FalseE | TrueE  -- boolean literals (F, T)
  | AddE Expr Expr  -- x + y
  | SubE Expr Expr  -- x - y
  | EqE  Expr Expr  -- x = y
  | OrE  Expr Expr  -- x | y
  | AndE Expr Expr  -- x & y
  deriving (Show)

expr :: Parser Expr
expr = chainl1 term op
  where op = AddE <$ char '+'
         <|> SubE <$ char '-'
         <|> EqE  <$ char '='
         <|> OrE  <$ char '|'
         <|> AndE <$ char '&'

term :: Parser Expr
term = IntE . read <$> some digit
   <|> FalseE <$ char 'F' <|> TrueE <$ char 'T'
   <|> parens expr

parens :: Parser a -> Parser a
parens = between (char '(') (char ')')

-- * Interpreter

data Value = BoolV Bool | IntV Int deriving (Eq, Show)

eval :: Expr -> Value
eval (IntE x) = IntV x
eval FalseE = BoolV False
eval TrueE = BoolV True
eval (AddE e1 e2)
  = let IntV v1 = eval e1  -- pattern match ensures right type
        IntV v2 = eval e2
    in  IntV (v1 + v2)
eval (SubE e1 e2)
  = let IntV v1 = eval e1
        IntV v2 = eval e2
    in  IntV (v1 - v2)
eval (EqE e1 e2) = BoolV (eval e1 == eval e2)  -- equal if same type and value
eval (OrE e1 e2)
  = let BoolV v1 = eval e1
        BoolV v2 = eval e2
    in  BoolV (v1 || v2)
eval (AndE e1 e2)
  = let BoolV v1 = eval e1
        BoolV v2 = eval e2
    in  BoolV (v1 && v2)

-- * Combined parser/interpreter with no intermediate AST

expr' :: Parser Value
expr' = chainl1 term' op
  where op = add <$ char '+'
         <|> sub <$ char '-'
         <|> eq  <$ char '='
         <|> or  <$ char '|'
         <|> and <$ char '&'
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
        eq  v1 v2 = BoolV $ v1 == v2
        or  (BoolV x) (BoolV y) = BoolV $ x || y
        and (BoolV x) (BoolV y) = BoolV $ x && y
term' :: Parser Value
term' = IntV . read <$> some digit
   <|> BoolV False <$ char 'F' <|> BoolV True <$ char 'T'
   <|> parens expr'

-- * Parser/interpreter with operator precendence

expr0 :: Parser Value
expr0 = chainl1 expr1 op
  where op = or  <$ char '|'
        or  (BoolV x) (BoolV y) = BoolV $ x || y
expr1 :: Parser Value
expr1 = chainl1 expr2 op
  where op = and <$ char '&'
        and (BoolV x) (BoolV y) = BoolV $ x && y
expr2 :: Parser Value
expr2 = chainl1 expr3 op
  where op = eq  <$ char '='
        eq  v1 v2 = BoolV $ v1 == v2
expr3 :: Parser Value
expr3 = chainl1 term'' op
  where op = add <$ char '+'  -- two operators at same precedence
         <|> sub <$ char '-'
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
term'' :: Parser Value
term'' = IntV . read <$> some digit
     <|> BoolV False <$ char 'F' <|> BoolV True <$ char 'T'
     <|> parens expr0

-- * Alternate implementation using buildExpressionParser

expr0' :: Parser Value
expr0' = buildExpressionParser table term''
  where table = [ [binary '+' add, binary '-' sub]
                , [binary '=' eq]
                , [binary '&' and]
                , [binary '|' or]
                ]
        binary c op = Infix (op <$ char c) AssocLeft
        add (IntV x) (IntV y) = IntV $ x + y
        sub (IntV x) (IntV y) = IntV $ x - y
        eq  v1 v2 = BoolV $ v1 == v2
        and (BoolV x) (BoolV y) = BoolV $ x && y
        or  (BoolV x) (BoolV y) = BoolV $ x || y

-- * Typed parser/interpreter with separate boolean and integer expressions

bexpr0 :: Parser Bool
bexpr0 = chainl1 bexpr1 op
  where op = (||) <$ char '|'
bexpr1 :: Parser Bool
bexpr1 = chainl1 bexpr2 op
  where op = (&&) <$ char '&'
bexpr2 :: Parser Bool
bexpr2 = False <$ char 'F' <|> True <$ char 'T'
     <|> try eqexpr
     <|> parens bexpr0
     where eqexpr = (==) <$> iexpr3 <* char '=' <*> iexpr3  -- this can't chain now
iexpr3 :: Parser Int
iexpr3 = chainl1 iterm op
  where op = (+) <$ char '+'
         <|> (-) <$ char '-'
iterm :: Parser Int
iterm = read <$> some digit
     <|> parens iexpr3

-- * Alternate definition of eqexpr to allow 4=2+2=1+3

eqexpr' = do
  x:xs <- sepBy1 iexpr3 (char '=')
  return $ all (==x) xs


来源: stackexchange

问:
How to find the first number in a text field using a MySQL query?
I like to return only the first number of a text stored in a column of a database table.
User have put in page ranges into a field like 'p.2-5' or 'page 2 to 5' or '2 - 5'.
I am interested in the '2' here.

I tried to

```<code>  SELECT SUBSTR(the_field, LOCATE('2', the_field, 1)) AS 'the_number'
  FROM the_table
</code>```

and it works. But how to get ANY number?

I tried

```<code>  SELECT SUBSTR(the_field, LOCATE(REGEXP '[0-9], the_field, 1)) AS 'the_number'
  FROM the_table
</code>```

but this time I get an error.

Any ideas?

答:
Just use REGEXP_SUBSTR():

```<code>SELECT REGEXP_SUBSTR(`the_field`,'^[0-9]+') AS `the_number` FROM `the_table`;
</code>```

Notes:

I'm using MySQL Server v8.0.

This pattern assumes that the_field is trimmed. Otherwise, use TRIM() first.

ContentLicense: CC BY-SA 3.0

Body:
I like to return only the first number of a text stored in a column of a database table.
User have put in page ranges into a field like 'p.2-5' or 'page 2 to 5' or '2 - 5'.
I am interested in the '2' here.

I tried to

  SELECT SUBSTR(the_field, LOCATE('2', the_field, 1)) AS 'the_number'
  FROM the_table

and it works. But how to get ANY number?

I tried

  SELECT SUBSTR(the_field, LOCATE(REGEXP '[0-9], the_field, 1)) AS 'the_number'
  FROM the_table

but this time I get an error.

Any ideas?

Body:
Just use REGEXP_SUBSTR():

SELECT REGEXP_SUBSTR(`the_field`,'^[0-9]+') AS `the_number` FROM `the_table`;

Notes:

I'm using MySQL Server v8.0.

This pattern assumes that the_field is trimmed. Otherwise, use TRIM() first.

ContentLicense: CC BY-SA 4.0


问:
How to select letters from a string until predefined point?
I would like to extract all consonants in a string before the first vowel, ideally without using regex. If I have the word truck for example I would like to extract the "tr", for "street" I would like to extract "str".

I tried the following but received the error wrong number of arguments (given 0, expected 1) for the execution of the block in vowels.

Can someone explain where the error is or suggest an easier way to do this?

```<code>vowels = ["a", "e", "i", "o", "u"]

def vowels(words)
  letters = words.split("")
  consonants = []
  letters.each do |letter|
    consonants << letter until vowels.include?(letter)
  end
  consonants
end
</code>```

答:
Using take_while is semantic.

```<code>word.chars.take_while { |c| vowels.none? c }.join
</code>```

Body:
I would like to extract all consonants in a string before the first vowel, ideally without using regex. If I have the word truck for example I would like to extract the "tr", for "street" I would like to extract "str".

I tried the following but received the error wrong number of arguments (given 0, expected 1) for the execution of the block in vowels.

Can someone explain where the error is or suggest an easier way to do this?

vowels = ["a", "e", "i", "o", "u"]

def vowels(words)
  letters = words.split("")
  consonants = []
  letters.each do |letter|
    consonants << letter until vowels.include?(letter)
  end
  consonants
end

Body:
Using take_while is semantic.

word.chars.take_while { |c| vowels.none? c }.join


问:
Image in flex container not centering after defining width and height
I'm doing some personal portfolio using css flex box. what I'm trying to do is to center the image horizontally, It did center but the problem is after I defined width and height to img the image is at the start or left now not in the center.

This is what it looks like when centered and not defining the width and height

.center-img{
  border-radius: 50%;
  display:flex;
  flex-direction:column;
  justify-content:center;
  text-align:center;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="center-img">
  <img src="https://png2.kisspng.com/sh/06560124247439e98f5534b17467b691/L0KzQYm3VcA5N5DBiZH0aYP2gLBuTgV0baMye9H2cIX3dcO0ifNwdqQyiAt8dHXwPbTvif5me5Yyj9t3ZD33ecXzhb1kd516hdC2NXHpQYW5VBZlO5JnTKo3M0e7RIa8VccyPWM6T6g5NkO8SIeATwBvbz==/kisspng-user-computer-icons-system-chinese-wind-title-column-5af1427fd3ab48.378455571525760639867.png" alt="user">
  <h1>User</h1>
</div></code>```

And this is what it look liked after defining width and height

.center-img{
  width:100px;
  height:100px;
  border-radius: 50%;
  display:flex;
  flex-direction:column;
  justify-content:center;
  text-align:center;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="center-img">
  <img src="https://png2.kisspng.com/sh/06560124247439e98f5534b17467b691/L0KzQYm3VcA5N5DBiZH0aYP2gLBuTgV0baMye9H2cIX3dcO0ifNwdqQyiAt8dHXwPbTvif5me5Yyj9t3ZD33ecXzhb1kd516hdC2NXHpQYW5VBZlO5JnTKo3M0e7RIa8VccyPWM6T6g5NkO8SIeATwBvbz==/kisspng-user-computer-icons-system-chinese-wind-title-column-5af1427fd3ab48.378455571525760639867.png" alt="user">
  <h1>User</h1>
</div></code>```

I expect that after defining the width and height of the image it would not affect the position of the image. so it should be in the center.
thank you!

答:
You need to wrangle the dimensions of the items inside.

The image can be controlled with max-width and max-height relative to the container. I added the red border so you can see the container easier.

Also, the h1 element comes with big font-size and margin by default so need to set values for those too.

.center-img {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center; /* change text-align to align-items */
  border: 1px red solid; /* this is just so you can easily see the container */
}

.center-img img {
  max-width: 100%; /* dimensions relative to the container size */
  max-height: 40%; /* dimensions relative to the container size */
  height: auto; /* keep aspect ratio */
  width: auto; /* keep aspect ratio */
}

.center-img h1 {
  margin: 5px 0 0; /* h1 has default margin-top and margin-bottom */
  font-size: 18px; /* Set this to a reasonable size */
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="center-img">
  <img src="https://png2.kisspng.com/sh/06560124247439e98f5534b17467b691/L0KzQYm3VcA5N5DBiZH0aYP2gLBuTgV0baMye9H2cIX3dcO0ifNwdqQyiAt8dHXwPbTvif5me5Yyj9t3ZD33ecXzhb1kd516hdC2NXHpQYW5VBZlO5JnTKo3M0e7RIa8VccyPWM6T6g5NkO8SIeATwBvbz==/kisspng-user-computer-icons-system-chinese-wind-title-column-5af1427fd3ab48.378455571525760639867.png"
    alt="user">
  <h1>User</h1>
</div></code>```

Body:
I'm doing some personal portfolio using css flex box. what I'm trying to do is to center the image horizontally, It did center but the problem is after I defined width and height to img the image is at the start or left now not in the center.

This is what it looks like when centered and not defining the width and height

.center-img{
  border-radius: 50%;
  display:flex;
  flex-direction:column;
  justify-content:center;
  text-align:center;
}

User

And this is what it look liked after defining width and height

.center-img{
  width:100px;
  height:100px;
  border-radius: 50%;
  display:flex;
  flex-direction:column;
  justify-content:center;
  text-align:center;
}

User

I expect that after defining the width and height of the image it would not affect the position of the image. so it should be in the center.
thank you!

Body:
You need to wrangle the dimensions of the items inside.

The image can be controlled with max-width and max-height relative to the container. I added the red border so you can see the container easier.

Also, the h1 element comes with big font-size and margin by default so need to set values for those too.

.center-img {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center; /* change text-align to align-items */
  border: 1px red solid; /* this is just so you can easily see the container */
}

.center-img img {
  max-width: 100%; /* dimensions relative to the container size */
  max-height: 40%; /* dimensions relative to the container size */
  height: auto; /* keep aspect ratio */
  width: auto; /* keep aspect ratio */
}

.center-img h1 {
  margin: 5px 0 0; /* h1 has default margin-top and margin-bottom */
  font-size: 18px; /* Set this to a reasonable size */
}

<div class="center-img">
  <img src="https://png2.kisspng.com/sh/06560124247439e98f5534b17467b691/L0KzQYm3VcA5N5DBiZH0aYP2gLBuTgV0baMye9H2cIX3dcO0ifNwdqQyiAt8dHXwPbTvif5me5Yyj9t3ZD33ecXzhb1kd516hdC2NXHpQYW5VBZlO5JnTKo3M0e7RIa8VccyPWM6T6g5NkO8SIeATwBvbz==/kisspng-user-computer-icons-system-chinese-wind-title-column-5af1427fd3ab48.378455571525760639867.png"
    alt="user">
  <h1>User</h1>
</div>


问:
How to use @ExceptionHandler in Spring Interceptor？
I am using springmvc to create restful api for client， I have an interceptor for checking the accesstoken.

```<code>public class AccessTokenInterceptor extends HandlerInterceptorAdapter
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
    if (handler instanceof HandlerMethod)
    {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Authorize authorizeRequired = handlerMethod.getMethodAnnotation(Authorize.class);
        if (authorizeRequired != null)
        {
            String token = request.getHeader("accesstoken");
            ValidateToken(token);
        }
    }
    return true;
}

protected long ValidateToken(String token)
{
    AccessToken accessToken = TokenImpl.GetAccessToken(token);

    if (accessToken != null)
    {
        if (accessToken.getExpirationDate().compareTo(new Date()) > 0)
        {
            throw new TokenExpiredException();
        }
        return accessToken.getUserId();
    }
    else
    {
        throw new InvalidTokenException();
    }
}
</code>```

And in my controller, I use @ExceptionHandler to handle exceptions, the code to handle InvalidTokenException looks like

```<code>@ExceptionHandler(InvalidTokenException.class)
public @ResponseBody
Response handleInvalidTokenException(InvalidTokenException e)
{
    Log.p.debug(e.getMessage());
    Response rs = new Response();
    rs.setErrorCode(ErrorCode.INVALID_TOKEN);
    return rs;
}
</code>```

But unfortunately the exception throwed in preHandle method is not caught by the exception handler defined in controller.

Can any one give me an solution of handling the exception?
PS: My controller method produce both json and xml using code below:

```<code>@RequestMapping(value = "login", method = RequestMethod.POST, produces =
{
    "application/xml", "application/json"
})
</code>```

答:
If you use @EnableWebMvc annotation anywhere through ur application, HandlerExceptionResolverComposite (subclass of HandlerExceptionResolver) will be applied. Since we know that HandlerExceptionResolver will be invoked not only through the controller method execution cycle but also before/after controller (e.g. HandlerInterceptor. check here), HandlerExceptionResolverComposite will be invoked.
Since by default, HandlerExceptionResolverComposite will register 3 resolvers, and one of them is: ExceptionHandlerExceptionResolver, based on
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.html#doResolveHandlerMethodException-javax.servlet.http.HttpServletRequest-javax.servlet.http.HttpServletResponse-org.springframework.web.method.HandlerMethod-java.lang.Exception-

it will try to find controller level @ExceptionHandler annotation and forward the exception to that exception handler. (see "doResolveHandlerMethodException" in above link)

So as long as you have @EnableWebMvc (why not?), your @ExceptionHandler should be able to catch exception thrown from spring interceptor.

Body:
I am using springmvc to create restful api for client， I have an interceptor for checking the accesstoken.

public class AccessTokenInterceptor extends HandlerInterceptorAdapter
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
    if (handler instanceof HandlerMethod)
    {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Authorize authorizeRequired = handlerMethod.getMethodAnnotation(Authorize.class);
        if (authorizeRequired != null)
        {
            String token = request.getHeader("accesstoken");
            ValidateToken(token);
        }
    }
    return true;
}

protected long ValidateToken(String token)
{
    AccessToken accessToken = TokenImpl.GetAccessToken(token);

    if (accessToken != null)
    {
        if (accessToken.getExpirationDate().compareTo(new Date()) > 0)
        {
            throw new TokenExpiredException();
        }
        return accessToken.getUserId();
    }
    else
    {
        throw new InvalidTokenException();
    }
}

And in my controller, I use @ExceptionHandler to handle exceptions, the code to handle InvalidTokenException looks like

@ExceptionHandler(InvalidTokenException.class)
public @ResponseBody
Response handleInvalidTokenException(InvalidTokenException e)
{
    Log.p.debug(e.getMessage());
    Response rs = new Response();
    rs.setErrorCode(ErrorCode.INVALID_TOKEN);
    return rs;
}

But unfortunately the exception throwed in preHandle method is not caught by the exception handler defined in controller.

Can any one give me an solution of handling the exception?
PS: My controller method produce both json and xml using code below:

@RequestMapping(value = "login", method = RequestMethod.POST, produces =
{
    "application/xml", "application/json"
})


问:
Check whether string in palindrome : C# code efficiency
I am coming from C background and recently started writing in C# so please don't mind if my question seems somewhat basic. Basically, i want to write a function which will return true if string is palindrome and false if not.

The string may contain characters like space, ',', ':' which i have to ignore. I have written the code as below

```<code>    static bool IsPalindrome(string s)
    {
        s = s.Replace(" ", "");
        s = s.Replace(",", "");
        s = s.Replace(":", "");

        int j = s.Length - 1;

        for(int i = 0; i < s.Length/2; i++)
        {
            if(s[i].ToString().Equals(s[j].ToString(),StringComparison.InvariantCultureIgnoreCase))
            {
                j--;
            }
            else
            {
                return false;
            }
        }
        return true;

    }
</code>```

where the function will be invoked with the following string

```<code>string s = "A man, a plan, a canal: Panama";
</code>```

I read in the documentation that in C#, string are immutable so each time i do a operation like replace or ToString, a new copy is getting created.

So i wanted to check that
i).  Is this code efficient?
ii). If not, how to make it more efficient.

答:
You don't need to use .Replace or create new strings, you can just skip the unwanted characters as you compare.

```<code>static bool IsPalindrome(string s)
{
    var i = 0;
    var j = s.Length - 1;
    while (j > i)
    {
        if (s[i] == ':' || s[i] == ',' || s[i] == ' ')
        {
            i++;
            continue;
        }
        if (s[j] == ':' || s[j] == ',' || s[j] == ' ')
        {
            j--;
            continue;
        }

        if (char.ToUpperInvariant(s[i++]) != char.ToUpperInvariant(s[j--])) return false;
    }

    return true;
}
</code>```

Body:
I am coming from C background and recently started writing in C# so please don't mind if my question seems somewhat basic. Basically, i want to write a function which will return true if string is palindrome and false if not.

The string may contain characters like space, ',', ':' which i have to ignore. I have written the code as below

    static bool IsPalindrome(string s)
    {
        s = s.Replace(" ", "");
        s = s.Replace(",", "");
        s = s.Replace(":", "");

        int j = s.Length - 1;

        for(int i = 0; i < s.Length/2; i++)
        {
            if(s[i].ToString().Equals(s[j].ToString(),StringComparison.InvariantCultureIgnoreCase))
            {
                j--;
            }
            else
            {
                return false;
            }
        }
        return true;

    }

where the function will be invoked with the following string

string s = "A man, a plan, a canal: Panama";

I read in the documentation that in C#, string are immutable so each time i do a operation like replace or ToString, a new copy is getting created.

So i wanted to check that
i).  Is this code efficient?
ii). If not, how to make it more efficient.

Body:
You don't need to use .Replace or create new strings, you can just skip the unwanted characters as you compare.

static bool IsPalindrome(string s)
{
    var i = 0;
    var j = s.Length - 1;
    while (j > i)
    {
        if (s[i] == ':' || s[i] == ',' || s[i] == ' ')
        {
            i++;
            continue;
        }
        if (s[j] == ':' || s[j] == ',' || s[j] == ' ')
        {
            j--;
            continue;
        }

        if (char.ToUpperInvariant(s[i++]) != char.ToUpperInvariant(s[j--])) return false;
    }

    return true;
}


问:
How to link DLL file in classpath
I kept my DLL file in Apache's lib folder and try to run my server. It shows

unsatisfied link error no DLL found in java.library.classpath.

How to make Tomcat Catalina to point to my DLL file in lib folder.

答:
Make sure to pass -Djava.library.path=/directory/with/your/dll/file inside Catalina startup script.

Alternatively, you can use _JAVA_OPTIONS variable. But make sure to pass all the options here as _JAVA_OPTIONS overrides anything else.

Title: How to link DLL file in classpath


问:
Is there a way to calculate an average using JS code?
I’m trying to calculate an average using Javascript, and have following code to show you. I am building an application where I need to calculate an average score.

I have been trying to build a calculator using JavaScript in which you click on two radio buttons and trying to get an average after you click a button. You can find the HTML code for the radio buttons below:

```<code><div class="container">
    <div class="row">
        <div style = "text-align:center">
            APS Calculator
            <form action=""  id="calculator" onsubmit="fn1 ()>
            Maths
            <p>
            <input type = "radio" name = "APS Maths" value="9">9<br>
            <input type = "radio" name = "APS Maths" value="8">8<br>
            <input type = "radio" name = "APS Maths" value="7">7<br>
            <input type = "radio" name = "APS Maths" value="6">6<br>
            <input type = "radio" name = "APS Maths" value="5">5<br>
            <input type = "radio" name = "APS Maths" value="4">4<br>
            <input type = "radio" name = "APS Maths" value="3">3<br>
            <input type = "radio" name = "APS Maths" value="2">2<br>
            <input type = "radio" name = "APS Maths" value="1">1<br>
            <input type = "radio" name = "APS Maths" value="0">0<br>
            </p>
            English
            <p>
            <input type = "radio" name = "APS English" value="9">9<br>
            <input type = "radio" name = "APS English" value="8">8<br>
            <input type = "radio" name = "APS English" value="7">7<br>
            <input type = "radio" name = "APS English" value="6">6<br>
            <input type = "radio" name = "APS English" value="5">5<br>
            <input type = "radio" name = "APS English" value="4">4<br>
            <input type = "radio" name = "APS English" value="3">3<br>
            <input type = "radio" name = "APS English" value="2">2<br>
            <input type = "radio" name = "APS English" value="1">1<br>
            <input type = "radio" name = "APS English" value="0">0<br>

            <br>
                <button onclick="fn1 ()" id = "btn1"> Click Me</button>

            </p>
            </form>
        </div>
        </div>
    </div>
</code>```

Whenever I click the button after choosing two radio buttons, the output comes out as either "Your APS is : NaN" or there is no output at all. Can I find a way to output an average based on the buttons that i have clicked?

Here is the JavaScript code:

var EnglishStudent = parseInt(document.getElementsByName('APS English'));
var MathsStudent = parseInt(document.getElementsByName('APS Maths'));
var avg = (EnglishStudent + MathsStudent) / 2;

function fn1(EnglishStudent, MathsStudent)

{
  var EnglishStudent = parseInt(document.getElementsByName('APS English'));
  var MathsStudent = parseInt(document.getElementsByName('APS Maths'));
  var avg = (EnglishStudent + MathsStudent) / 2;
  return avg;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="container">
    <div class="row">
        <div style = "text-align:center">
            APS Calculator
            <form action=""  id="calculator" onsubmit="fn1 ()>
            Maths
            <p>
            <input type = "radio" name = "APS Maths" value="9">9<br>
            <input type = "radio" name = "APS Maths" value="8">8<br>
            <input type = "radio" name = "APS Maths" value="7">7<br>
            <input type = "radio" name = "APS Maths" value="6">6<br>
            <input type = "radio" name = "APS Maths" value="5">5<br>
            <input type = "radio" name = "APS Maths" value="4">4<br>
            <input type = "radio" name = "APS Maths" value="3">3<br>
            <input type = "radio" name = "APS Maths" value="2">2<br>
            <input type = "radio" name = "APS Maths" value="1">1<br>
            <input type = "radio" name = "APS Maths" value="0">0<br>
            </p>
            English
            <p>
            <input type = "radio" name = "APS English" value="9">9<br>
            <input type = "radio" name = "APS English" value="8">8<br>
            <input type = "radio" name = "APS English" value="7">7<br>
            <input type = "radio" name = "APS English" value="6">6<br>
            <input type = "radio" name = "APS English" value="5">5<br>
            <input type = "radio" name = "APS English" value="4">4<br>
            <input type = "radio" name = "APS English" value="3">3<br>
            <input type = "radio" name = "APS English" value="2">2<br>
            <input type = "radio" name = "APS English" value="1">1<br>
            <input type = "radio" name = "APS English" value="0">0<br>

            <br>
                <button onclick="fn1 ()" id = "btn1"> Click Me</button>

            </p>
            </form>
        </div>
        </div>
    </div></code>```

Thank you for your help.

答:
In addition to the other issues mentioned, CSS selectors can be used to find the selected radios :

var a = document.querySelector("input[name='APS Maths']:checked");
var b = document.querySelector("input[name='APS English']:checked");

if (a && b)
  document.write( (+a.value + +b.value) / 2 )```
<pre class="snippet-code-html lang-html prettyprint-override"><code><input type="radio" name="APS Maths" value="8">8
<input type="radio" name="APS Maths" value="7" checked>7
<input type="radio" name="APS Maths" value="6">6
<br>
<input type="radio" name="APS English" value="4">4
<input type="radio" name="APS English" value="3" checked>3
<input type="radio" name="APS English" value="2">2
<br>
Average:</code>```

Body:
I’m trying to calculate an average using Javascript, and have following code to show you. I am building an application where I need to calculate an average score.

I have been trying to build a calculator using JavaScript in which you click on two radio buttons and trying to get an average after you click a button. You can find the HTML code for the radio buttons below:

            APS Calculator
            <form action=""  id="calculator" onsubmit="fn1 ()>
            Maths

            <input type = "radio" name = "APS Maths" value="9">9

            <input type = "radio" name = "APS Maths" value="8">8

            <input type = "radio" name = "APS Maths" value="7">7

            <input type = "radio" name = "APS Maths" value="6">6

            <input type = "radio" name = "APS Maths" value="5">5

            <input type = "radio" name = "APS Maths" value="4">4

            <input type = "radio" name = "APS Maths" value="3">3

            <input type = "radio" name = "APS Maths" value="2">2

            <input type = "radio" name = "APS Maths" value="1">1

            <input type = "radio" name = "APS Maths" value="0">0

            English

            <input type = "radio" name = "APS English" value="9">9

            <input type = "radio" name = "APS English" value="8">8

            <input type = "radio" name = "APS English" value="7">7

            <input type = "radio" name = "APS English" value="6">6

            <input type = "radio" name = "APS English" value="5">5

            <input type = "radio" name = "APS English" value="4">4

            <input type = "radio" name = "APS English" value="3">3

            <input type = "radio" name = "APS English" value="2">2

            <input type = "radio" name = "APS English" value="1">1

            <input type = "radio" name = "APS English" value="0">0

                <button onclick="fn1 ()" id = "btn1"> Click Me</button>

            </form>

Whenever I click the button after choosing two radio buttons, the output comes out as either "Your APS is : NaN" or there is no output at all. Can I find a way to output an average based on the buttons that i have clicked?

Here is the JavaScript code:

var EnglishStudent = parseInt(document.getElementsByName('APS English'));
var MathsStudent = parseInt(document.getElementsByName('APS Maths'));
var avg = (EnglishStudent + MathsStudent) / 2;

function fn1(EnglishStudent, MathsStudent)

{
  var EnglishStudent = parseInt(document.getElementsByName('APS English'));
  var MathsStudent = parseInt(document.getElementsByName('APS Maths'));
  var avg = (EnglishStudent + MathsStudent) / 2;
  return avg;
}

            APS Calculator
            <form action=""  id="calculator" onsubmit="fn1 ()>
            Maths

            <input type = "radio" name = "APS Maths" value="9">9

            <input type = "radio" name = "APS Maths" value="8">8

            <input type = "radio" name = "APS Maths" value="7">7

            <input type = "radio" name = "APS Maths" value="6">6

            <input type = "radio" name = "APS Maths" value="5">5

            <input type = "radio" name = "APS Maths" value="4">4

            <input type = "radio" name = "APS Maths" value="3">3

            <input type = "radio" name = "APS Maths" value="2">2

            <input type = "radio" name = "APS Maths" value="1">1

            <input type = "radio" name = "APS Maths" value="0">0

            English

            <input type = "radio" name = "APS English" value="9">9

            <input type = "radio" name = "APS English" value="8">8

            <input type = "radio" name = "APS English" value="7">7

            <input type = "radio" name = "APS English" value="6">6

            <input type = "radio" name = "APS English" value="5">5

            <input type = "radio" name = "APS English" value="4">4

            <input type = "radio" name = "APS English" value="3">3

            <input type = "radio" name = "APS English" value="2">2

            <input type = "radio" name = "APS English" value="1">1

            <input type = "radio" name = "APS English" value="0">0

                <button onclick="fn1 ()" id = "btn1"> Click Me</button>

            </form>

Thank you for your help.

Body:
In addition to the other issues mentioned, CSS selectors can be used to find the selected radios :

var a = document.querySelector("input[name='APS Maths']:checked");
var b = document.querySelector("input[name='APS English']:checked");

if (a && b)
  document.write( (+a.value + +b.value) / 2 )

<input type="radio" name="APS Maths" value="8">8
<input type="radio" name="APS Maths" value="7" checked>7
<input type="radio" name="APS Maths" value="6">6
<br>
<input type="radio" name="APS English" value="4">4
<input type="radio" name="APS English" value="3" checked>3
<input type="radio" name="APS English" value="2">2
<br>
Average:


问:
How to add numbers between strings in a list?
I have a mixed list with strings and ints and I need to get to the sum of the numbers between each strings. Ideally the end result would be a list of tuples since each string and following numbers belong together (so order is important).

I can extract the number with iteration using isinstance but the actual list is very large and I sometimes I have 1 or 2 numbers for each string.

my_list = ['a', 2, 1, 'b', 3, 'h', 50, 4, 'd', 4, 'v', 20, 7]

ideal_output = [('a', 3) ('b', 3), ('h', 54), ('d', 4), (v, 27)]

```

答:
With functools.reduce function:

```<code>from functools import reduce

def accum(prev, curr):    # prev - previous item, curr - current item
    if prev == [] or isinstance(curr, str):
        prev.append((curr, 0))
    elif isinstance(curr, int):
        prev[-1] = (prev[-1][0], prev[-1][1] + curr)
    return prev

my_list = ['a', 2, 1, 'b', 3, 'h', 50, 4, 'd', 4, 'v', 20, 7]
res = reduce(accum, my_list, [])   # [] is initializer
print(res)
</code>```

The output:

```<code>[('a', 3), ('b', 3), ('h', 54), ('d', 4), ('v', 27)]
</code>```

Body:
With functools.reduce function:

from functools import reduce

def accum(prev, curr):    # prev - previous item, curr - current item
    if prev == [] or isinstance(curr, str):
        prev.append((curr, 0))
    elif isinstance(curr, int):
        prev[-1] = (prev[-1][0], prev[-1][1] + curr)
    return prev

my_list = ['a', 2, 1, 'b', 3, 'h', 50, 4, 'd', 4, 'v', 20, 7]
res = reduce(accum, my_list, [])   # [] is initializer
print(res)

The output:

[('a', 3), ('b', 3), ('h', 54), ('d', 4), ('v', 27)]


问:
How to define an Intent inside a Lambda expression
I'm making an app in Android Studio and I want to go from my LoginActivity to my MainActivity with an Intent from within an OnCompleteListener().

I've tried with:

firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() {
    @Override
    public void onComplete(@NonNull Task task) {
        if(task.isSuccessful()) {
            Intent mainActivity = new Intent(getApplicationContext(), MainActivity.class);
            startActivity(mainActivity);
            finish();
        }
    }
});

//and

firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() {
    @Override
    public void onComplete(@NonNull Task task) {
        if(task.isSuccessful()) {
            Intent mainActivity = new Intent(LoginActivity.this, MainActivity.class);
            startActivity(mainActivity);
            finish();
        }
    }
});
```

With both parameters, the app compiled properly but stopped when the signInWithEmailAndPassword() method was triggered.

Is there any other parameter I can use?

答:
Intent should be created in the same way as before. The LoginActivity.this refers to this instance of the outer LoginActivity class where is the inner anonymous class used. It probably isn't meant to substitute the getApplicationContext().

As far as you tagged the lambda, your wish is to shorten the anonymous class implementation to a lambda expression, here you go:

```<code>firebaseAuth.signInWithEmailAndPassword(email, password)
    .addOnCompleteListener(this, task -> {
         if (task.isSuccessful()) {
             Intent mainActivity = new Intent(getApplicationContext(), MainActivity.class);
             startActivity(mainActivity);
             finish();
         }
    });
</code>```

Remember, the Intent instantiation is not related to the lambda expression. The key part is shortening the:

```<code>new OnCompleteListener() {
    @Override
    public void onComplete(@NonNull Task task) { ... }
}
</code>```

... to ...

```<code>task -> { ... }
</code>```

Body:
I'm making an app in Android Studio and I want to go from my LoginActivity to my MainActivity with an Intent from within an OnCompleteListener().

I've tried with:

firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() {
    @Override
    public void onComplete(@NonNull Task task) {
        if(task.isSuccessful()) {
            Intent mainActivity = new Intent(getApplicationContext(), MainActivity.class);
            startActivity(mainActivity);
            finish();
        }
    }
});

//and

firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() {
    @Override
    public void onComplete(@NonNull Task task) {
        if(task.isSuccessful()) {
            Intent mainActivity = new Intent(LoginActivity.this, MainActivity.class);
            startActivity(mainActivity);
            finish();
        }
    }
});

With both parameters, the app compiled properly but stopped when the signInWithEmailAndPassword() method was triggered.

Is there any other parameter I can use?

Body:
Intent should be created in the same way as before. The LoginActivity.this refers to this instance of the outer LoginActivity class where is the inner anonymous class used. It probably isn't meant to substitute the getApplicationContext().

As far as you tagged the lambda, your wish is to shorten the anonymous class implementation to a lambda expression, here you go:

firebaseAuth.signInWithEmailAndPassword(email, password)
    .addOnCompleteListener(this, task -> {
         if (task.isSuccessful()) {
             Intent mainActivity = new Intent(getApplicationContext(), MainActivity.class);
             startActivity(mainActivity);
             finish();
         }
    });

Remember, the Intent instantiation is not related to the lambda expression. The key part is shortening the:

new OnCompleteListener() {
    @Override
    public void onComplete(@NonNull Task task) { ... }
}

... to ...

task -> { ... }


问:
Remote mysql connection works in workbench but not in python
I setup a mysql server (using mariadb) and database on my raspi and am now trying to connect to it from my MacBook.

Version:
mysql  Ver 15.1 Distrib 10.1.38-MariaDB, for debian-linux-gnueabihf (armv7l) using readline 5.2

The connection works in Workbench(on the Mac)but I can't get it to connect in python or command line

the /etc/my.cnf on the raspi looks like this:

bind-address = 0.0.0.0

[mysqld]

I have added a superuser with all permissions and am trying to connect on my Mac command line with this:

```<code>mysql -u {superuser} -p {superuser} -h '192.168.x.x' -P '3307' -D {securities_master}
</code>```

Which doesn’t work.

In python I have tried different variations of this:

host = '192.168.x.x'
user='superuser'
password='superuser'
database='securities_master'

import mysql.connector
cnx = mysql.connector.connect(user=user, password=password, host=host, port='3307')
print(cnx.get_server_info()) ```

command line returns this:
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 3

python script returns this:
pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '192.168.x.x' ([Errno 61] Connection refused)")

Workbench connection is solid

答:
You mentioned that mysql -u {superuser} -p {superuser} -h '192.168.x.x' -P '22' -D {securities_master} Works properly.

Here, the mysql connection port is 22. If that really works, then

```<code>host = '192.168.x.x'
user='superuser'
password='superuser'
database='securities_master'

import pymysql.cursors
connection = pymysql.connect(host=host,
                             port=3306,
                             user=user,
                             password=password,
                             db=database,
                             charset='utf8',
                             cursorclass=pymysql.cursors.DictCursor)
</code>```

should be

```<code>host = '192.168.x.x'
user='superuser'
password='superuser'
database='securities_master'

import pymysql.cursors
connection = pymysql.connect(host=host,
                             port=22,
                             user=user,
                             password=password,
                             db=database,
                             charset='utf8',
                             cursorclass=pymysql.cursors.DictCursor)
</code>```

The port number has changed to 3306 to 22.

you can check it with

```<code>pymysql.connect(db='securities_master', user='superuser', passwd='superuser', host='192.168.x.x', port=22)
</code>```

Body:
I setup a mysql server (using mariadb) and database on my raspi and am now trying to connect to it from my MacBook.

Version:
mysql  Ver 15.1 Distrib 10.1.38-MariaDB, for debian-linux-gnueabihf (armv7l) using readline 5.2

The connection works in Workbench(on the Mac)but I can't get it to connect in python or command line

the /etc/my.cnf on the raspi looks like this:

bind-address = 0.0.0.0

[mysqld]

I have added a superuser with all permissions and am trying to connect on my Mac command line with this:

mysql -u {superuser} -p {superuser} -h '192.168.x.x' -P '3307' -D {securities_master}

Which doesn’t work.

In python I have tried different variations of this:

host = '192.168.x.x'
user='superuser'
password='superuser'
database='securities_master'

import mysql.connector
cnx = mysql.connector.connect(user=user, password=password, host=host, port='3307')
print(cnx.get_server_info())

command line returns this:
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 3

python script returns this:
pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '192.168.x.x' ([Errno 61] Connection refused)")

Workbench connection is solid

Body:
You mentioned that mysql -u {superuser} -p {superuser} -h '192.168.x.x' -P '22' -D {securities_master} Works properly.

Here, the mysql connection port is 22. If that really works, then

host = '192.168.x.x'
user='superuser'
password='superuser'
database='securities_master'

import pymysql.cursors
connection = pymysql.connect(host=host,
                             port=3306,
                             user=user,
                             password=password,
                             db=database,
                             charset='utf8',
                             cursorclass=pymysql.cursors.DictCursor)

should be

host = '192.168.x.x'
user='superuser'
password='superuser'
database='securities_master'

import pymysql.cursors
connection = pymysql.connect(host=host,
                             port=22,
                             user=user,
                             password=password,
                             db=database,
                             charset='utf8',
                             cursorclass=pymysql.cursors.DictCursor)

The port number has changed to 3306 to 22.

you can check it with

pymysql.connect(db='securities_master', user='superuser', passwd='superuser', host='192.168.x.x', port=22)


问:
What packages do I need for a working CPAN tool chain under cygwin64?
There are a couple of perl modules I often use on my *nix systems (FreeBSD, Linux, Mac). I always install these from cpan. Earlier this year I needed to use some of these on a 64-bit Windows system, and in about 2 hours I got the then-most-recent Strawberry Perl package installed, and from cpan I installed the modules of my desire the same way I used to do under *nix. Everything worked as expected.

On another 64-bit Windows system I am now attempting to set up a cygwin64 environment instead of installing Strawberry Perl. There are a handful of tools we need on that system, and those are already working fine under cygwin64, so it seems like a good idea to add the new perl functionality to the already existing cygwin64 environment. To test this possibility without messing with the production environment, I am performing trial/error setups on a separate, clean Windows system.

I downloaded the now current cygwin64 installer, and can get all the tools we required in the past installed fine. I can also get perl5 installed. But installing modules via "cpan install" does not work.
Unfortunatelly, I am not really aware of the *nix packages that cpan depends on, because all on my unices (and apparently with Strawberry Perl under Windows too) every dependency is installed automatically, and I never had to care about these.
My cygwin64 environment obviously misses some packages required by the build process run by cpan. But cpan in cygwin64 does a very bad job of communicating what is missing or what is wrong.

I tried installing multiple combinations of clang, gcc, mingw and other developer tools using the cygwin installer, but still could not get "cpan install desired::module" working. Depending on the package mixture I used, I get different errors (or signs of errors).

As a fairly reliable starting point, could you please give me a list of cygwin packages I should most certainly install, in order to have an environment where "cpan install ..." is supposed to succeed.

Addition#1:

If I install only the most basic cygwin packages (zsh, perl) and those that come anyway, I end up with this ...

```<code>keve@cygtest ~
$ perl -v

This is perl 5, version 26, subversion 3 (v5.26.3) built for     x86_64-cygwin-threads-multi
(with 7 registered patches, see perl -V for more detail)

Copyright 1987-2018, Larry Wall

Perl may be copied only under the terms of either the Artistic License or     the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

keve@cygtest ~
$ curl --version
curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL
Release-Date: [unreleased]
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps     telnet tftp
Features: AsynchDNS IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL
</code>```

Any of make, gmake, cmake, nmake, gcc, clang results in a "command not found" response.

Starting cpan does this ...

```<code>$ cpan
Loading internal null logger. Install Log::Log4perl for logging messages
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <</home/Valaki/.cpan/CPAN/MyConfig.pm>>

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes]

Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl5/5.26/App/Cpan.pm line 669, <STDIN> line 1.
 <install_help>

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib]

 ALERT: 'make' is an essential tool for building perl Modules.
Please make sure you have 'make' (or some equivalent) working.

Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
</code>```

and that "Press SPACE and ENTER" line keeps filling my screen until I press Ctrl+C.

So, I start the Cygwin installer again, and install the devel/make package. That way I have this ...

```<code>$ make -v
GNU Make 4.2.1
Built for x86_64-unknown-cygwin
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ cpan
Loading internal null logger. Install Log::Log4perl for logging messages
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <</home/Valaki/.cpan/CPAN/MyConfig.pm>>

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes]

Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl5/5.26/App/Cpan.pm line 669, <STDIN> line 1.
 <install_help>

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib]

Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
</code>```

This time there is no warning about "make" missing, but the same "Press SPACE and ENTER" line fills the screen. There is still that "uninitialised $what", and the warning about not having proper permissions to folders. Which I have seen in questions by others, usually fixed by reinstalling the perl package with the most recent one (I have the most recent one).

So, what package do I miss?
Or did I make a wrong choice above by accepting the default?
Please note: I have installed additional devel packages with my earlier attempts. But to keep things simple for now, I only have "perl" and "make".

Addition#2

Following the answers by Håkon and mob, I started the cygwin installer again, and installed the recommended packages. So now I have devel/binutils, devel/clang, devel/cmake, devel/gcc-core, devel/gcc-g++, gccmakedep, and make installed. Also available is curl, which was already present so I did not need to install (perhaps came as a dependency).

Unfortunately, I still get this when starting "cpan":

```<code>$ cpan
Loading internal null logger. Install Log::Log4perl for logging messages
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <</home/Valaki/.cpan/CPAN/MyConfig.pm>>

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes]

Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl5/5.26/App/Cpan.pm line 669, <STDIN> line 1.
 <install_help>

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib]

Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
</code>```

Regarding the $what warning:
Lines 660 to 670 of Cpan.pm go like this ...

```<code>BEGIN {
my $scalar = '';

sub _hook_into_CPANpm_report
    {
    no warnings 'redefine';

    *CPAN::Shell::myprint = sub {
        my($self,$what) = @_;
        $scalar .= $what;
</code>```

I can get rid of the warning by modifying line 669 to this ...

```<code>$scalar .= ($what // '');
</code>```

... but this does not solve the problem of why $what is undefined anyway. However, I still end up seeing that "Press SPACE and ENTER to disable curl" filling up the screen. And the same happens if I type "manual" and hit Enter instead of accepting the default local::lib option.

答:
Things took an interesting turn. I noticed that even though I had curl from the very beginning (came with the most basic, default cygwin environment), I never installed it (not via the cygwin installer).

```<code>keve@cygtest ~
$ curl --version
curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL
Release-Date: [unreleased]
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps     telnet tftp
Features: AsynchDNS IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL

keve@cygtest ~
$ which curl
/cygdrive/c/Windows/system32/curl
</code>```

And there is a curl package available to mark for install. So I installed Net/curl via cygwin setup, and then got this.

```<code>keve@cygtest ~
$ which curl
/usr/bin/curl

keve@cygtest ~
$ curl --version
curl 7.65.0 (x86_64-pc-cygwin) libcurl/7.65.0 OpenSSL/1.1.1b zlib/1.2.11 brotli/1.0.7 libidn2/2.0.4 libpsl/0.18.0 (+libidn2/2.0.2) libssh/0.8.7/openssl/zlib nghttp2/1.37.0
Release-Date: 2019-05-22
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS brotli Debug GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz Metalink NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP TrackMemory UnixSockets

keve@cygtest ~
$ which -a curl
/usr/bin/curl
/cygdrive/c/Windows/system32/curl
</code>```

At that point, cpan no longer printed the "Press SPACE and ENTER to disable curl" message, but started to behave as expected.

```<code>keve@cygtest ~
$ cpan
Loading internal null logger. Install Log::Log4perl for logging messages
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <</home/keve/.cpan/CPAN/MyConfig.pm>>

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes]

Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl5/5.26/App/Cpan.pm line 669, <STDIN> line 1.
 <install_help>

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib]

Autoconfiguration complete.

Attempting to bootstrap local::lib...

Writing /home/keve/.cpan/CPAN/MyConfig.pm for bootstrap...
commit: wrote '/home/keve/.cpan/CPAN/MyConfig.pm'
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/01mailrc.txt.gz
Reading '/home/keve/.cpan/sources/authors/01mailrc.txt.gz'
............................................................................DONE
Fetching with HTTP::Tiny:
http://www.cpan.org/modules/02packages.details.txt.gz
Reading '/home/keve/.cpan/sources/modules/02packages.details.txt.gz'
  Database was generated on Sat, 01 Jun 2019 09:17:02 GMT
  HTTP::Date not available
.............
  New CPAN.pm version (v2.26) available.
  [Currently running version is v2.18]
  You might want to try
    install CPAN
    reload cpan
  to both upgrade CPAN.pm and run the new version without leaving
  the current session.

...............................................................DONE
Fetching with HTTP::Tiny:
http://www.cpan.org/modules/03modlist.data.gz
Reading '/home/keve/.cpan/sources/modules/03modlist.data.gz'
DONE
Writing /home/keve/.cpan/Metadata
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/id/H/HA/HAARG/local-lib-2.000024.tar.gz
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/id/H/HA/HAARG/CHECKSUMS
Checksum for /home/keve/.cpan/sources/authors/id/H/HA/HAARG/local-lib-2.000024.tar.gz ok
'YAML' not installed, will not store persistent state
Configuring H/HA/HAARG/local-lib-2.000024.tar.gz with Makefile.PL
Attempting to create directory /home/keve/perl5

Checking if your kit is complete...
Looks good
Generating a Unix-style Makefile
Writing Makefile for local::lib
Writing MYMETA.yml and MYMETA.json
  HAARG/local-lib-2.000024.tar.gz
  /usr/bin/perl Makefile.PL --bootstrap -- OK
Running make for H/HA/HAARG/local-lib-2.000024.tar.gz
cp lib/local/lib.pm blib/lib/local/lib.pm
cp lib/POD2/PT_BR/local/lib.pod blib/lib/POD2/PT_BR/local/lib.pod
cp lib/POD2/DE/local/lib.pod blib/lib/POD2/DE/local/lib.pod
cp lib/lib/core/only.pm blib/lib/lib/core/only.pm
Manifying 4 pod documents
  HAARG/local-lib-2.000024.tar.gz
  /usr/bin/make -- OK
Running make test
PERL_DL_NONLAZY=1 "/usr/bin/perl.exe" "-I/home/keve/perl5/lib/perl5" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/bad_variables.t ...... ok
t/carp-mismatch.t ...... ok
t/classmethod.t ........ ok
t/de-dup.t ............. ok
t/lib-core-only.t ...... ok
t/pipeline.t ........... ok
t/shell.t .............. ok
t/stackable.t .......... ok
t/subroutine-in-inc.t .. ok
t/taint-mode.t ......... ok
All tests successful.
Files=10, Tests=172, 29 wallclock secs ( 0.03 usr  0.17 sys +  4.24 cusr 11.30 csys = 15.74 CPU)
Result: PASS
  HAARG/local-lib-2.000024.tar.gz
  /usr/bin/make test -- OK
Running make install
Manifying 4 pod documents
Installing /home/keve/perl5/lib/perl5/lib/core/only.pm
Installing /home/keve/perl5/lib/perl5/local/lib.pm
Installing /home/keve/perl5/lib/perl5/POD2/DE/local/lib.pod
Installing /home/keve/perl5/lib/perl5/POD2/PT_BR/local/lib.pod
Installing /home/keve/perl5/man/man3/lib.core.only.3pm
Installing /home/keve/perl5/man/man3/local.lib.3pm
Installing /home/keve/perl5/man/man3/POD2.DE.local.lib.3pm
Installing /home/keve/perl5/man/man3/POD2.PT_BR.local.lib.3pm
Appending installation info to /home/keve/perl5/lib/perl5/x86_64-cygwin-threads-multi/perllocal.pod
  HAARG/local-lib-2.000024.tar.gz
  /usr/bin/make install  -- OK

local::lib is installed. You must now add the following environment variables
to your shell configuration files (or registry, if you are on Windows) and
then restart your command line shell and CPAN before installing modules:

PATH="/home/keve/perl5/bin${PATH:+:${PATH}}"; export PATH;
PERL5LIB="/home/keve/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB;
PERL_LOCAL_LIB_ROOT="/home/keve/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT;
PERL_MB_OPT="--install_base \"/home/keve/perl5\""; export PERL_MB_OPT;
PERL_MM_OPT="INSTALL_BASE=/home/keve/perl5"; export PERL_MM_OPT;

Would you like me to append that to /home/keve/.bashrc now? [yes]

commit: wrote '/home/keve/.cpan/CPAN/MyConfig.pm'

You can re-run configuration any time with 'o conf init' in the CPAN shell
Terminal does not support AddHistory.

cpan shell -- CPAN exploration and modules installation (v2.18)
Enter 'h' for help.

cpan[1]>
</code>```

And now I can start building modules by the usual "install desired::package" method. So I finally got where I wanted to get.
Interestingly, each module I wanted to build failed to build. But at least they failed in a way that I am familiar with from *nix. So this is now another problem for another day.

To answer my original question: to get a working "cpan" under cygwin, you must install at least these packages . . .

devel/binutils

devel/clang

devel/cmake

devel/gcc-core

devel/gcc-g++

devel/gccmakedep

devel/make

Net/curl

The last one, Net/curl is extremely important. Because the basic cygwin environment does have a functional curl already, but "cpan" does not work with that. You must install the Net/curl package via cygwin setup. That will get rid of the "Press SPACE and ENTER to disable curl" messages filling up the window upon running "cpan".

Body:
There are a couple of perl modules I often use on my *nix systems (FreeBSD, Linux, Mac). I always install these from cpan. Earlier this year I needed to use some of these on a 64-bit Windows system, and in about 2 hours I got the then-most-recent Strawberry Perl package installed, and from cpan I installed the modules of my desire the same way I used to do under *nix. Everything worked as expected.

On another 64-bit Windows system I am now attempting to set up a cygwin64 environment instead of installing Strawberry Perl. There are a handful of tools we need on that system, and those are already working fine under cygwin64, so it seems like a good idea to add the new perl functionality to the already existing cygwin64 environment. To test this possibility without messing with the production environment, I am performing trial/error setups on a separate, clean Windows system.

I downloaded the now current cygwin64 installer, and can get all the tools we required in the past installed fine. I can also get perl5 installed. But installing modules via "cpan install" does not work.
Unfortunatelly, I am not really aware of the *nix packages that cpan depends on, because all on my unices (and apparently with Strawberry Perl under Windows too) every dependency is installed automatically, and I never had to care about these.
My cygwin64 environment obviously misses some packages required by the build process run by cpan. But cpan in cygwin64 does a very bad job of communicating what is missing or what is wrong.

I tried installing multiple combinations of clang, gcc, mingw and other developer tools using the cygwin installer, but still could not get "cpan install desired::module" working. Depending on the package mixture I used, I get different errors (or signs of errors).

As a fairly reliable starting point, could you please give me a list of cygwin packages I should most certainly install, in order to have an environment where "cpan install ..." is supposed to succeed.

Addition#1:

If I install only the most basic cygwin packages (zsh, perl) and those that come anyway, I end up with this ...

keve@cygtest ~
$ perl -v

This is perl 5, version 26, subversion 3 (v5.26.3) built for     x86_64-cygwin-threads-multi
(with 7 registered patches, see perl -V for more detail)

Copyright 1987-2018, Larry Wall

Perl may be copied only under the terms of either the Artistic License or     the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

keve@cygtest ~
$ curl --version
curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL
Release-Date: [unreleased]
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps     telnet tftp
Features: AsynchDNS IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL

Any of make, gmake, cmake, nmake, gcc, clang results in a "command not found" response.

Starting cpan does this ...

$ cpan
Loading internal null logger. Install Log::Log4perl for logging messages
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <</home/Valaki/.cpan/CPAN/MyConfig.pm>>

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes]

Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl5/5.26/App/Cpan.pm line 669, <STDIN> line 1.
 <install_help>

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib]

 ALERT: 'make' is an essential tool for building perl Modules.
Please make sure you have 'make' (or some equivalent) working.

Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl

and that "Press SPACE and ENTER" line keeps filling my screen until I press Ctrl+C.

So, I start the Cygwin installer again, and install the devel/make package. That way I have this ...

$ make -v
GNU Make 4.2.1
Built for x86_64-unknown-cygwin
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ cpan
Loading internal null logger. Install Log::Log4perl for logging messages
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <</home/Valaki/.cpan/CPAN/MyConfig.pm>>

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes]

Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl5/5.26/App/Cpan.pm line 669, <STDIN> line 1.
 <install_help>

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib]

Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl

This time there is no warning about "make" missing, but the same "Press SPACE and ENTER" line fills the screen. There is still that "uninitialised $what", and the warning about not having proper permissions to folders. Which I have seen in questions by others, usually fixed by reinstalling the perl package with the most recent one (I have the most recent one).

So, what package do I miss?
Or did I make a wrong choice above by accepting the default?
Please note: I have installed additional devel packages with my earlier attempts. But to keep things simple for now, I only have "perl" and "make".

Addition#2

Following the answers by Håkon and mob, I started the cygwin installer again, and installed the recommended packages. So now I have devel/binutils, devel/clang, devel/cmake, devel/gcc-core, devel/gcc-g++, gccmakedep, and make installed. Also available is curl, which was already present so I did not need to install (perhaps came as a dependency).

Unfortunately, I still get this when starting "cpan":

$ cpan
Loading internal null logger. Install Log::Log4perl for logging messages
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <</home/Valaki/.cpan/CPAN/MyConfig.pm>>

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes]

Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl5/5.26/App/Cpan.pm line 669, <STDIN> line 1.
 <install_help>

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib]

Press SPACE and ENTER to disable curl
Press SPACE and ENTER to disable curl

Regarding the $what warning:
Lines 660 to 670 of Cpan.pm go like this ...

BEGIN {
my $scalar = '';

sub _hook_into_CPANpm_report
    {
    no warnings 'redefine';

    *CPAN::Shell::myprint = sub {
        my($self,$what) = @_;
        $scalar .= $what;

I can get rid of the warning by modifying line 669 to this ...

$scalar .= ($what // '');

... but this does not solve the problem of why $what is undefined anyway. However, I still end up seeing that "Press SPACE and ENTER to disable curl" filling up the screen. And the same happens if I type "manual" and hit Enter instead of accepting the default local::lib option.

Body:
Things took an interesting turn. I noticed that even though I had curl from the very beginning (came with the most basic, default cygwin environment), I never installed it (not via the cygwin installer).

keve@cygtest ~
$ curl --version
curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL
Release-Date: [unreleased]
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps     telnet tftp
Features: AsynchDNS IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL

keve@cygtest ~
$ which curl
/cygdrive/c/Windows/system32/curl

And there is a curl package available to mark for install. So I installed Net/curl via cygwin setup, and then got this.

keve@cygtest ~
$ which curl
/usr/bin/curl

keve@cygtest ~
$ curl --version
curl 7.65.0 (x86_64-pc-cygwin) libcurl/7.65.0 OpenSSL/1.1.1b zlib/1.2.11 brotli/1.0.7 libidn2/2.0.4 libpsl/0.18.0 (+libidn2/2.0.2) libssh/0.8.7/openssl/zlib nghttp2/1.37.0
Release-Date: 2019-05-22
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS brotli Debug GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz Metalink NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP TrackMemory UnixSockets

keve@cygtest ~
$ which -a curl
/usr/bin/curl
/cygdrive/c/Windows/system32/curl

At that point, cpan no longer printed the "Press SPACE and ENTER to disable curl" message, but started to behave as expected.

keve@cygtest ~
$ cpan
Loading internal null logger. Install Log::Log4perl for logging messages
Sorry, we have to rerun the configuration dialog for CPAN.pm due to
some missing parameters. Configuration will be written to
 <</home/keve/.cpan/CPAN/MyConfig.pm>>

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes]

Use of uninitialized value $what in concatenation (.) or string at /usr/share/perl5/5.26/App/Cpan.pm line 669, <STDIN> line 1.
 <install_help>

Warning: You do not have write permission for Perl library directories.

To install modules, you need to configure a local Perl library directory or
escalate your privileges.  CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available).  You may also
resolve this problem manually if you need to customize your setup.

What approach do you want?  (Choose 'local::lib', 'sudo' or 'manual')
 [local::lib]

Autoconfiguration complete.

Attempting to bootstrap local::lib...

Writing /home/keve/.cpan/CPAN/MyConfig.pm for bootstrap...
commit: wrote '/home/keve/.cpan/CPAN/MyConfig.pm'
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/01mailrc.txt.gz
Reading '/home/keve/.cpan/sources/authors/01mailrc.txt.gz'
............................................................................DONE
Fetching with HTTP::Tiny:
http://www.cpan.org/modules/02packages.details.txt.gz
Reading '/home/keve/.cpan/sources/modules/02packages.details.txt.gz'
  Database was generated on Sat, 01 Jun 2019 09:17:02 GMT
  HTTP::Date not available
.............
  New CPAN.pm version (v2.26) available.
  [Currently running version is v2.18]
  You might want to try
    install CPAN
    reload cpan
  to both upgrade CPAN.pm and run the new version without leaving
  the current session.

...............................................................DONE
Fetching with HTTP::Tiny:
http://www.cpan.org/modules/03modlist.data.gz
Reading '/home/keve/.cpan/sources/modules/03modlist.data.gz'
DONE
Writing /home/keve/.cpan/Metadata
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/id/H/HA/HAARG/local-lib-2.000024.tar.gz
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/id/H/HA/HAARG/CHECKSUMS
Checksum for /home/keve/.cpan/sources/authors/id/H/HA/HAARG/local-lib-2.000024.tar.gz ok
'YAML' not installed, will not store persistent state
Configuring H/HA/HAARG/local-lib-2.000024.tar.gz with Makefile.PL
Attempting to create directory /home/keve/perl5

Checking if your kit is complete...
Looks good
Generating a Unix-style Makefile
Writing Makefile for local::lib
Writing MYMETA.yml and MYMETA.json
  HAARG/local-lib-2.000024.tar.gz
  /usr/bin/perl Makefile.PL --bootstrap -- OK
Running make for H/HA/HAARG/local-lib-2.000024.tar.gz
cp lib/local/lib.pm blib/lib/local/lib.pm
cp lib/POD2/PT_BR/local/lib.pod blib/lib/POD2/PT_BR/local/lib.pod
cp lib/POD2/DE/local/lib.pod blib/lib/POD2/DE/local/lib.pod
cp lib/lib/core/only.pm blib/lib/lib/core/only.pm
Manifying 4 pod documents
  HAARG/local-lib-2.000024.tar.gz
  /usr/bin/make -- OK
Running make test
PERL_DL_NONLAZY=1 "/usr/bin/perl.exe" "-I/home/keve/perl5/lib/perl5" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/bad_variables.t ...... ok
t/carp-mismatch.t ...... ok
t/classmethod.t ........ ok
t/de-dup.t ............. ok
t/lib-core-only.t ...... ok
t/pipeline.t ........... ok
t/shell.t .............. ok
t/stackable.t .......... ok
t/subroutine-in-inc.t .. ok
t/taint-mode.t ......... ok
All tests successful.
Files=10, Tests=172, 29 wallclock secs ( 0.03 usr  0.17 sys +  4.24 cusr 11.30 csys = 15.74 CPU)
Result: PASS
  HAARG/local-lib-2.000024.tar.gz
  /usr/bin/make test -- OK
Running make install
Manifying 4 pod documents
Installing /home/keve/perl5/lib/perl5/lib/core/only.pm
Installing /home/keve/perl5/lib/perl5/local/lib.pm
Installing /home/keve/perl5/lib/perl5/POD2/DE/local/lib.pod
Installing /home/keve/perl5/lib/perl5/POD2/PT_BR/local/lib.pod
Installing /home/keve/perl5/man/man3/lib.core.only.3pm
Installing /home/keve/perl5/man/man3/local.lib.3pm
Installing /home/keve/perl5/man/man3/POD2.DE.local.lib.3pm
Installing /home/keve/perl5/man/man3/POD2.PT_BR.local.lib.3pm
Appending installation info to /home/keve/perl5/lib/perl5/x86_64-cygwin-threads-multi/perllocal.pod
  HAARG/local-lib-2.000024.tar.gz
  /usr/bin/make install  -- OK

local::lib is installed. You must now add the following environment variables
to your shell configuration files (or registry, if you are on Windows) and
then restart your command line shell and CPAN before installing modules:

PATH="/home/keve/perl5/bin${PATH:+:${PATH}}"; export PATH;
PERL5LIB="/home/keve/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB;
PERL_LOCAL_LIB_ROOT="/home/keve/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT;
PERL_MB_OPT="--install_base \"/home/keve/perl5\""; export PERL_MB_OPT;
PERL_MM_OPT="INSTALL_BASE=/home/keve/perl5"; export PERL_MM_OPT;

Would you like me to append that to /home/keve/.bashrc now? [yes]

commit: wrote '/home/keve/.cpan/CPAN/MyConfig.pm'

You can re-run configuration any time with 'o conf init' in the CPAN shell
Terminal does not support AddHistory.

cpan shell -- CPAN exploration and modules installation (v2.18)
Enter 'h' for help.

cpan[1]>

And now I can start building modules by the usual "install desired::package" method. So I finally got where I wanted to get.
Interestingly, each module I wanted to build failed to build. But at least they failed in a way that I am familiar with from *nix. So this is now another problem for another day.

To answer my original question: to get a working "cpan" under cygwin, you must install at least these packages . . .

devel/binutils

devel/clang

devel/cmake

devel/gcc-core

devel/gcc-g++

devel/gccmakedep

devel/make

Net/curl

The last one, Net/curl is extremely important. Because the basic cygwin environment does have a functional curl already, but "cpan" does not work with that. You must install the Net/curl package via cygwin setup. That will get rid of the "Press SPACE and ENTER to disable curl" messages filling up the window upon running "cpan".