or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

conversions.mdgeneric.mdhlist.mdhmap.mdindex.mdlift.mdnat.mdpoly.mdrecords.mdsized.mdsybclass.mdtypeable.mdtypeoperators.md

conversions.mddocs/

0

# Type-safe Conversions

1

2

Shapeless provides type-safe bidirectional conversions between various Scala data structures including tuples, functions, and HLists. These conversions maintain type safety and enable seamless interoperability between different representations of the same data.

3

4

## Tuple ↔ HList Conversions

5

6

### HLister Type Class

7

8

```scala { .api }

9

/**

10

* Converts Products (tuples) to HLists

11

*/

12

trait HLister[T <: Product] {

13

type Out <: HList

14

def apply(t: T): Out

15

}

16

```

17

18

### Tupler Type Class

19

20

```scala { .api }

21

/**

22

* Converts HLists to tuples (when possible)

23

*/

24

trait Tupler[L <: HList] {

25

type Out <: Product

26

def apply(l: L): Out

27

}

28

```

29

30

### Tuples Object

31

32

```scala { .api }

33

/**

34

* Provides enhanced operations for tuple conversions

35

*/

36

object Tuples {

37

trait TupleOps[L <: HList] {

38

def hlisted: L

39

}

40

41

implicit def tupleOps[T <: Product](t: T)(implicit hlister: HLister[T]): TupleOps[hlister.Out]

42

43

object hlisted extends Poly1 // Converts Tuples to HLists

44

object tupled extends Poly1 // Converts HLists to Tuples

45

}

46

```

47

48

**Usage Examples:**

49

50

```scala

51

import shapeless._

52

import syntax.std.tuple._

53

54

// Convert tuple to HList

55

val tuple = (42, "hello", true)

56

val hlist = tuple.hlisted // Int :: String :: Boolean :: HNil

57

58

// Convert HList to tuple

59

val backToTuple = hlist.tupled // (Int, String, Boolean) = (42, "hello", true)

60

61

// Polymorphic conversion

62

import Tuples._

63

64

val pairs = ((1, "a"), (2, "b"), (3, "c"))

65

val hlistPairs = (pairs._1.hlisted, pairs._2.hlisted, pairs._3.hlisted)

66

// (1 :: "a" :: HNil, 2 :: "b" :: HNil, 3 :: "c" :: HNil)

67

```

68

69

### Product Arity

70

71

```scala { .api }

72

/**

73

* Witnesses the arity of a Product type

74

*/

75

trait ProductArity[P <: Product] {

76

type N <: Nat // Arity as natural number

77

}

78

```

79

80

**Usage Examples:**

81

82

```scala

83

import shapeless._

84

85

// Get arity information at type level

86

def showArity[P <: Product, N <: Nat]

87

(p: P)

88

(implicit arity: ProductArity.Aux[P, N], toInt: ToInt[N]): Int = toInt()

89

90

val pair = (1, "hello")

91

val triple = (1, "hello", true)

92

93

val pairArity = showArity(pair) // 2

94

val tripleArity = showArity(triple) // 3

95

```

96

97

## Function Conversions

98

99

### Function to HList Function

100

101

```scala { .api }

102

/**

103

* Converts ordinary functions to HList functions

104

*/

105

trait FnHLister[F] {

106

type Out

107

def apply(f: F): Out

108

}

109

```

110

111

### HList Function to Function

112

113

```scala { .api }

114

/**

115

* Converts HList functions to ordinary functions

116

*/

117

trait FnUnHLister[F] {

118

type Out

119

def apply(f: F): Out

120

}

121

```

122

123

### Functions Object

124

125

```scala { .api }

126

/**

127

* Provides enhanced operations for function conversions

128

*/

129

object Functions {

130

trait FnHListOps[HLFn] {

131

def hlisted: HLFn

132

}

133

134

trait FnUnHListOps[F] {

135

def unhlisted: F

136

}

137

}

138

```

139

140

**Usage Examples:**

141

142

```scala

143

import shapeless._

144

import syntax.std.function._

145

146

// Convert regular function to HList function

147

val add: (Int, Int) => Int = _ + _

148

val hlistAdd = add.hlisted // (Int :: Int :: HNil) => Int

149

150

// Apply HList function

151

val args = 5 :: 3 :: HNil

152

val result = hlistAdd(args) // 8

153

154

// Convert back to regular function

155

val regularAdd = hlistAdd.unhlisted // (Int, Int) => Int

156

val result2 = regularAdd(7, 2) // 9

157

158

// More complex example

159

val processData: (String, Int, Boolean) => String =

160

(name, age, active) => s"$name is $age years old and ${if (active) "active" else "inactive"}"

161

162

val hlistProcessor = processData.hlisted

163

val data = "Alice" :: 25 :: true :: HNil

164

val processed = hlistProcessor(data) // "Alice is 25 years old and active"

165

```

166

167

### Function Arity Support

168

169

Shapeless provides function conversion support for functions of arity 0 through 22:

170

171

```scala

172

import shapeless._

173

import syntax.std.function._

174

175

// Nullary function

176

val getValue: () => String = () => "constant"

177

val hlistGetValue = getValue.hlisted // HNil => String

178

val value = hlistGetValue(HNil) // "constant"

179

180

// Unary function

181

val double: Int => Int = _ * 2

182

val hlistDouble = double.hlisted // (Int :: HNil) => Int

183

val doubled = hlistDouble(5 :: HNil) // 10

184

185

// Higher arity functions

186

val combine5: (Int, String, Boolean, Double, Char) => String =

187

(i, s, b, d, c) => s"$i-$s-$b-$d-$c"

188

189

val hlistCombine5 = combine5.hlisted

190

val args5 = 42 :: "test" :: true :: 3.14 :: 'x' :: HNil

191

val combined = hlistCombine5(args5) // "42-test-true-3.14-x"

192

```

193

194

## Traversable Conversions

195

196

### FromTraversable Type Class

197

198

```scala { .api }

199

/**

200

* Type-safe conversion from Traversables to HLists

201

*/

202

trait FromTraversable[Out <: HList] {

203

def apply(l: GenTraversable[_]): Option[Out]

204

}

205

```

206

207

### Traversables Object

208

209

```scala { .api }

210

/**

211

* Provides enhanced operations for traversable conversions

212

*/

213

object Traversables {

214

trait TraversableOps {

215

def toHList[L <: HList](implicit fl: FromTraversable[L]): Option[L]

216

}

217

}

218

```

219

220

**Usage Examples:**

221

222

```scala

223

import shapeless._

224

import syntax.std.traversable._

225

226

// Convert List to HList with specific type structure

227

val mixedList: List[Any] = List(42, "hello", true)

228

val hlistOpt: Option[Int :: String :: Boolean :: HNil] = mixedList.toHList

229

230

hlistOpt match {

231

case Some(hlist) =>

232

val i: Int = hlist.head // 42

233

val s: String = hlist.tail.head // "hello"

234

val b: Boolean = hlist.tail.tail.head // true

235

case None =>

236

println("Conversion failed - type mismatch")

237

}

238

239

// Safe conversion - returns None on type mismatch

240

val wrongTypes: List[Any] = List("not", "an", "int")

241

val failedConversion: Option[Int :: String :: Boolean :: HNil] = wrongTypes.toHList

242

// failedConversion: None

243

244

// Convert collections of uniform type

245

val numbers = List(1, 2, 3)

246

val numberHList: Option[Int :: Int :: Int :: HNil] = numbers.toHList

247

```

248

249

## Generic Conversions

250

251

### Automatic Conversions

252

253

Shapeless provides automatic conversions between equivalent representations:

254

255

```scala

256

import shapeless._

257

258

// Case class to HList (requires Generic)

259

case class Person(name: String, age: Int, active: Boolean)

260

261

val person = Person("Bob", 30, true)

262

// Conversion to HList happens through Generic (covered in generic.md)

263

264

// Automatic tuple/HList interop in operations

265

val tuple = (1, "hello", true)

266

val hlist = 42 :: "world" :: false :: HNil

267

268

// Can zip tuple with HList (after conversion)

269

val tupleAsHList = tuple.hlisted

270

val zipped = tupleAsHList.zip(hlist)

271

// (1, 42) :: ("hello", "world") :: (true, false) :: HNil

272

```

273

274

### Bidirectional Operations

275

276

```scala

277

import shapeless._

278

import syntax.std.tuple._

279

280

// Complex conversion pipeline

281

val data = ((1, "a"), (2, "b"), (3, "c"))

282

283

// Convert tuple of tuples to HList of HLists

284

val step1 = data.hlisted // (1, "a") :: (2, "b") :: (3, "c") :: HNil

285

val step2 = step1.map(hlisted) // Would require proper Poly1 setup

286

287

// Practical example with functions

288

val processor: ((String, Int)) => String = { case (name, age) => s"$name:$age" }

289

val hlistProcessor = processor.hlisted // ((String :: Int :: HNil)) => String

290

291

val inputs = ("Alice" :: 25 :: HNil) :: ("Bob" :: 30 :: HNil) :: HNil

292

// Process each input (would need proper mapping setup)

293

```

294

295

## Advanced Conversion Patterns

296

297

### Conditional Conversions

298

299

```scala

300

import shapeless._

301

302

// Convert only when types match exactly

303

def safeConvert[T <: Product, L <: HList]

304

(product: T)

305

(implicit hlister: HLister.Aux[T, L]): L = hlister(product)

306

307

val tuple2 = (42, "hello")

308

val tuple3 = (42, "hello", true)

309

310

val hlist2 = safeConvert(tuple2) // Int :: String :: HNil

311

val hlist3 = safeConvert(tuple3) // Int :: String :: Boolean :: HNil

312

```

313

314

### Type-preserving Operations

315

316

```scala

317

import shapeless._

318

import syntax.std.tuple._

319

import syntax.std.function._

320

321

// Round-trip conversion maintains types

322

def roundTrip[T <: Product, L <: HList]

323

(t: T)

324

(implicit

325

hlister: HLister.Aux[T, L],

326

tupler: Tupler.Aux[L, T]): T = {

327

328

val hlist = t.hlisted

329

// Could perform HList operations here

330

hlist.tupled

331

}

332

333

val original = (1, "test", true)

334

val afterRoundTrip = roundTrip(original)

335

// afterRoundTrip has same type and value as original

336

```

337

338

### Conversion Validation

339

340

```scala

341

import shapeless._

342

343

// Validate conversions at compile time

344

def validateConversion[T <: Product, L <: HList, T2 <: Product]

345

(t: T)

346

(implicit

347

hlister: HLister.Aux[T, L],

348

tupler: Tupler.Aux[L, T2],

349

ev: T =:= T2): T2 = {

350

351

t.hlisted.tupled

352

}

353

354

// This ensures the round-trip conversion preserves exact types

355

val validated = validateConversion((1, "hello"))

356

// Type is exactly (Int, String)

357

```

358

359

### Integration with Collections

360

361

```scala

362

import shapeless._

363

import syntax.std.tuple._

364

import syntax.std.traversable._

365

366

// Convert collection of tuples to collection of HLists

367

val tupleList = List((1, "a"), (2, "b"), (3, "c"))

368

val hlistList = tupleList.map(_.hlisted)

369

// List[Int :: String :: HNil]

370

371

// Process and convert back

372

val processedHLists = hlistList.map(_.reverse)

373

val backToTuples = processedHLists.map(_.tupled)

374

// List[("a", 1), ("b", 2), ("c", 3)]

375

```

376

377

Type-safe conversions in shapeless enable seamless interoperability between different data representations while maintaining compile-time safety and type inference. This allows you to choose the most appropriate representation for each operation while avoiding runtime type errors.