or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

abi-processing.mdaddress-operations.mdcrypto-functions.mdcurrency-units.mddata-conversions.mddata-formatting.mdfunctional-programming.mdhexadecimal-utilities.mdindex.mdlogging-debugging.mdnetwork-information.mdtype-checking.md

functional-programming.mddocs/

0

# Functional Programming

1

2

Functional programming utilities including curried functions, return value transformers, and functional composition tools for advanced data processing patterns.

3

4

## Capabilities

5

6

### Return Value Transformers

7

8

Transform function return values with decorators.

9

10

```python { .api }

11

def apply_to_return_value(callback):

12

"""

13

Decorator to apply callback to function return value.

14

15

Args:

16

callback: Function to apply to return value

17

18

Returns:

19

Decorator function

20

"""

21

22

def to_tuple(func):

23

"""Decorator to convert return value to tuple."""

24

25

def to_list(func):

26

"""Decorator to convert return value to list."""

27

28

def to_set(func):

29

"""Decorator to convert return value to set."""

30

31

def to_dict(func):

32

"""Decorator to convert return value to dict."""

33

34

def to_ordered_dict(func):

35

"""Decorator to convert return value to OrderedDict."""

36

37

def flatten_return(func):

38

"""Decorator to flatten returned iterables."""

39

40

def reversed_return(func):

41

"""Decorator to reverse returned sequences."""

42

43

def sort_return(func):

44

"""Decorator to sort returned sequences."""

45

```

46

47

### Curried Functions

48

49

Access curried versions of functions for functional composition.

50

51

```python { .api }

52

from eth_utils.curried import (

53

# Address functions

54

to_checksum_address, is_checksum_address,

55

56

# Conversion functions

57

to_bytes, to_hex, to_int, to_text,

58

59

# ABI functions

60

filter_abi_by_type, filter_abi_by_name,

61

62

# Formatting functions

63

apply_formatter_if, apply_formatters_to_dict,

64

65

# Currency functions

66

from_wei, to_wei,

67

68

# Other utilities

69

clamp, get_logger

70

)

71

```

72

73

## Usage Examples

74

75

### Return Value Transformation

76

77

```python

78

from eth_utils import to_list, to_tuple, flatten_return, sort_return

79

80

@to_list

81

def get_transaction_hashes():

82

"""Get transaction hashes as generator, return as list."""

83

for i in range(5):

84

yield f"0x{i:064x}"

85

86

@to_tuple

87

def get_address_components(address):

88

"""Split address into components, return as tuple."""

89

return [address[:2], address[2:10], address[10:]]

90

91

@flatten_return

92

def get_nested_data():

93

"""Return nested data, flattened."""

94

return [[1, 2], [3, 4], [5, 6]]

95

96

@sort_return

97

def get_unsorted_addresses():

98

"""Return addresses in sorted order."""

99

return [

100

"0xd3CdA913deB6f67967B99D67aCDFa1712C293601",

101

"0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123",

102

"0xa1b2c3d4e5f6789012345678901234567890abcd"

103

]

104

105

# Usage

106

tx_hashes = get_transaction_hashes() # Returns list instead of generator

107

print(type(tx_hashes)) # <class 'list'>

108

109

components = get_address_components("0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123")

110

print(components) # ('0x', '742d35cc', '6634c053...')

111

112

flat_data = get_nested_data() # Returns [1, 2, 3, 4, 5, 6]

113

sorted_addrs = get_unsorted_addresses() # Returns sorted list

114

```

115

116

### Curried Function Composition

117

118

```python

119

from eth_utils.curried import to_checksum_address, filter_abi_by_type, apply_formatter_if, is_string

120

from functools import partial

121

122

# Create specialized formatters using curried functions

123

format_address = apply_formatter_if(is_string, to_checksum_address)

124

get_functions = filter_abi_by_type("function")

125

get_events = filter_abi_by_type("event")

126

127

# Use in data processing pipeline

128

def process_contract_data(contract_abi, addresses):

129

"""Process contract ABI and addresses with functional style."""

130

131

# Extract functions and events using curried functions

132

functions = get_functions(contract_abi)

133

events = get_events(contract_abi)

134

135

# Format all addresses using curried formatter

136

formatted_addresses = [format_address(addr) for addr in addresses]

137

138

return {

139

"functions": functions,

140

"events": events,

141

"addresses": formatted_addresses

142

}

143

144

# Example usage

145

contract_abi = [

146

{"type": "function", "name": "transfer"},

147

{"type": "event", "name": "Transfer"}

148

]

149

150

addresses = [

151

"0xd3cda913deb6f67967b99d67acdfa1712c293601",

152

b'\x74\x2d\x35\xcc\x66\x34\xc0\x53\x29\x25\xa3\xb8\xc1\x7b\x1e\x8b\x4e\x1d\x11\x23'

153

]

154

155

result = process_contract_data(contract_abi, addresses)

156

print(f"Found {len(result['functions'])} functions")

157

print(f"Formatted addresses: {result['addresses']}")

158

```

159

160

### Functional Data Pipeline

161

162

```python

163

from eth_utils import apply_to_return_value, to_list, flatten_return

164

from eth_utils.curried import to_int, from_wei

165

166

def create_pipeline(*transformers):

167

"""Create a functional processing pipeline."""

168

def pipeline(data):

169

result = data

170

for transformer in transformers:

171

result = transformer(result)

172

return result

173

return pipeline

174

175

# Create specialized transformers

176

@to_list

177

def extract_values(transactions):

178

"""Extract values from transaction objects."""

179

for tx in transactions:

180

yield tx.get('value', '0x0')

181

182

@apply_to_return_value(lambda values: [to_int(hexstr=v) for v in values])

183

def convert_hex_to_int(hex_values):

184

"""Convert hex values to integers."""

185

return hex_values

186

187

@apply_to_return_value(lambda values: [from_wei(v, 'ether') for v in values])

188

def convert_wei_to_ether(wei_values):

189

"""Convert wei values to ether."""

190

return wei_values

191

192

# Create processing pipeline

193

process_transaction_values = create_pipeline(

194

extract_values,

195

convert_hex_to_int,

196

convert_wei_to_ether

197

)

198

199

# Example usage

200

transactions = [

201

{"hash": "0x123...", "value": "0xde0b6b3a7640000"}, # 1 ETH

202

{"hash": "0x456...", "value": "0x1bc16d674ec80000"}, # 2 ETH

203

{"hash": "0x789...", "value": "0x2386f26fc10000"} # 0.01 ETH

204

]

205

206

ether_values = process_transaction_values(transactions)

207

print(f"Transaction values in ETH: {ether_values}")

208

```

209

210

### Functional Utilities with Currying

211

212

```python

213

from eth_utils.curried import apply_formatters_to_dict, to_checksum_address, to_int

214

from functools import partial

215

216

# Create reusable formatters using curried functions

217

transaction_formatters = {

218

'to': to_checksum_address,

219

'from': to_checksum_address,

220

'value': partial(to_int, hexstr=None),

221

'gasPrice': partial(to_int, hexstr=None),

222

'gasLimit': partial(to_int, hexstr=None),

223

'nonce': partial(to_int, hexstr=None)

224

}

225

226

# Create specialized formatter

227

format_transaction = apply_formatters_to_dict(transaction_formatters)

228

229

def process_transaction_batch(raw_transactions):

230

"""Process batch of raw transactions functionally."""

231

return [dict(format_transaction(tx)) for tx in raw_transactions]

232

233

# Example usage

234

raw_transactions = [

235

{

236

'to': '0xd3cda913deb6f67967b99d67acdfa1712c293601',

237

'from': '0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123',

238

'value': '0xde0b6b3a7640000',

239

'gasPrice': '0x4a817c800',

240

'gasLimit': '0x5208',

241

'nonce': '0x1'

242

}

243

]

244

245

formatted_transactions = process_transaction_batch(raw_transactions)

246

print(formatted_transactions[0]['to']) # Checksummed address

247

print(formatted_transactions[0]['value']) # Integer value

248

```

249

250

### Advanced Functional Patterns

251

252

```python

253

from eth_utils import apply_to_return_value, to_tuple, flatten_return

254

from eth_utils.curried import get_logger

255

from functools import wraps, reduce

256

import operator

257

258

def memoize(func):

259

"""Simple memoization decorator."""

260

cache = {}

261

262

@wraps(func)

263

def wrapper(*args, **kwargs):

264

key = str(args) + str(sorted(kwargs.items()))

265

if key not in cache:

266

cache[key] = func(*args, **kwargs)

267

return cache[key]

268

return wrapper

269

270

def compose(*functions):

271

"""Compose functions right to left."""

272

return reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x)

273

274

def pipe(*functions):

275

"""Pipe functions left to right."""

276

return reduce(lambda f, g: lambda x: g(f(x)), functions, lambda x: x)

277

278

# Create functional processing chains

279

@memoize

280

@to_tuple

281

def expensive_calculation(data):

282

"""Expensive calculation with memoization."""

283

# Simulate expensive operation

284

return [x * 2 for x in data]

285

286

# Function composition example

287

from eth_utils.curried import to_hex, keccak

288

289

# Compose functions: hash then encode

290

hash_and_encode = compose(to_hex, keccak)

291

292

# Use composed function

293

text_data = "Hello, Ethereum!"

294

result = hash_and_encode(text=text_data)

295

print(f"Hash and encoded: {result}")

296

297

# Pipeline example

298

process_data = pipe(

299

lambda x: x.upper(),

300

lambda x: x.replace(" ", "_"),

301

lambda x: f"processed_{x}"

302

)

303

304

processed = process_data("hello world")

305

print(processed) # processed_HELLO_WORLD

306

```

307

308

### Curried Utility Functions

309

310

```python

311

from eth_utils.curried import clamp, get_logger

312

from functools import partial

313

314

# Create specialized clamping functions

315

clamp_percentage = clamp(0, 100)

316

clamp_gas_price = clamp(1000000000, 100000000000) # 1-100 gwei

317

318

# Create specialized loggers

319

debug_logger = get_logger("debug")

320

error_logger = get_logger("error")

321

322

def validate_gas_price(gas_price):

323

"""Validate and clamp gas price."""

324

clamped = clamp_gas_price(gas_price)

325

326

if clamped != gas_price:

327

debug_logger.warning(f"Gas price clamped from {gas_price} to {clamped}")

328

329

return clamped

330

331

def validate_percentage(value):

332

"""Validate and clamp percentage value."""

333

return clamp_percentage(value)

334

335

# Examples

336

print(validate_gas_price(50000000000)) # Valid gas price

337

print(validate_gas_price(200000000000)) # Clamped to max

338

print(validate_percentage(150)) # Clamped to 100

339

```

340

341

### Functional Error Handling

342

343

```python

344

from eth_utils import apply_to_return_value

345

from functools import wraps

346

347

def safe_call(default_value=None):

348

"""Decorator for safe function calls with default return."""

349

def decorator(func):

350

@wraps(func)

351

def wrapper(*args, **kwargs):

352

try:

353

return func(*args, **kwargs)

354

except Exception as e:

355

print(f"Error in {func.__name__}: {e}")

356

return default_value

357

return wrapper

358

return decorator

359

360

def maybe(func):

361

"""Maybe monad-like decorator."""

362

@wraps(func)

363

def wrapper(value):

364

if value is None:

365

return None

366

try:

367

return func(value)

368

except Exception:

369

return None

370

return wrapper

371

372

# Usage with functional patterns

373

@safe_call(default_value=[])

374

@apply_to_return_value(list)

375

def safe_process_data(data):

376

"""Safely process data with default return."""

377

if not data:

378

raise ValueError("No data provided")

379

380

for item in data:

381

yield item * 2

382

383

@maybe

384

def safe_to_checksum(address):

385

"""Safely convert to checksum address."""

386

from eth_utils import to_checksum_address

387

return to_checksum_address(address)

388

389

# Examples

390

result1 = safe_process_data([1, 2, 3]) # [2, 4, 6]

391

result2 = safe_process_data(None) # [] (default)

392

393

addr1 = safe_to_checksum("0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123") # Checksummed

394

addr2 = safe_to_checksum("invalid") # None

395

addr3 = safe_to_checksum(None) # None

396

```

397

398

## Functional Programming Patterns

399

400

### Map, Filter, Reduce with eth-utils

401

402

```python

403

from eth_utils.curried import to_checksum_address, is_checksum_address, filter_abi_by_type

404

from functools import reduce

405

406

def functional_processing_example(addresses, contract_abi):

407

"""Example of functional processing with eth-utils."""

408

409

# Map: Convert all addresses to checksum format

410

checksum_addresses = list(map(to_checksum_address, addresses))

411

412

# Filter: Keep only valid checksum addresses

413

valid_addresses = list(filter(is_checksum_address, checksum_addresses))

414

415

# Reduce: Count total character length

416

total_length = reduce(lambda acc, addr: acc + len(addr), valid_addresses, 0)

417

418

# Extract functions using curried ABI filter

419

functions = filter_abi_by_type("function", contract_abi)

420

421

return {

422

"original_count": len(addresses),

423

"valid_count": len(valid_addresses),

424

"total_length": total_length,

425

"function_count": len(functions)

426

}

427

428

# Example usage

429

addresses = [

430

"0xd3cda913deb6f67967b99d67acdfa1712c293601",

431

"0x742d35cc6634c0532925a3b8c17b1e8b4e1d1123",

432

"invalid_address"

433

]

434

435

abi = [

436

{"type": "function", "name": "transfer"},

437

{"type": "function", "name": "approve"},

438

{"type": "event", "name": "Transfer"}

439

]

440

441

result = functional_processing_example(addresses, abi)

442

print(f"Processed {result['original_count']} addresses")

443

print(f"Found {result['valid_count']} valid addresses")

444

print(f"Found {result['function_count']} functions")

445

```